blob: 8b7778ddb2451e00ae554de4da61e3b4ce88813d [file] [log] [blame]
Jacob Garberfa8f5672020-05-18 13:18:19 -06001/* SPDX-License-Identifier: BSD-3-Clause */
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -07002
Jacob Garberfa8f5672020-05-18 13:18:19 -06003/*
4 * A lightweight TPM command library.
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -07005 *
6 * The general idea is that TPM commands are array of bytes whose
7 * fields are mostly compile-time constant. The goal is to build much
8 * of the commands at compile time (or build time) and change some of
9 * the fields at run time as needed. The code in
10 * utility/tlcl_generator.c builds structures containing the commands,
11 * as well as the offsets of the fields that need to be set at run
12 * time.
13 */
14
Daisuke Nojiri57990972014-07-15 19:47:32 -070015#include <assert.h>
Randall Spangler144c2282014-12-03 17:35:53 -080016#include <string.h>
Philipp Deppenwiesed88fb362017-10-18 20:26:18 +020017#include <security/tpm/tis.h>
Randall Spangler144c2282014-12-03 17:35:53 -080018#include <vb2_api.h>
Philipp Deppenwiese86391f12017-10-18 21:54:24 +020019#include <security/tpm/tss.h>
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +010020
Philipp Deppenwiesed88fb362017-10-18 20:26:18 +020021#include "tss_internal.h"
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +010022#include "tss_commands.h"
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -070023
Daisuke Nojiri57990972014-07-15 19:47:32 -070024#include <console/console.h>
25#define VBDEBUG(format, args...) printk(BIOS_DEBUG, format, ## args)
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -070026
Daisuke Nojiri57990972014-07-15 19:47:32 -070027static int tpm_send_receive(const uint8_t *request,
28 uint32_t request_length,
29 uint8_t *response,
30 uint32_t *response_length)
31{
32 size_t len = *response_length;
33 if (tis_sendrecv(request, request_length, response, &len))
34 return VB2_ERROR_UNKNOWN;
35 /* check 64->32bit overflow and (re)check response buffer overflow */
36 if (len > *response_length)
37 return VB2_ERROR_UNKNOWN;
38 *response_length = len;
39 return VB2_SUCCESS;
40}
41
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -070042/* Sets the size field of a TPM command. */
Lee Leahy342f8d62017-03-10 15:31:56 -080043static inline void set_tpm_command_size(uint8_t *buffer, uint32_t size)
44{
Daisuke Nojiri57990972014-07-15 19:47:32 -070045 to_tpm_uint32(buffer + sizeof(uint16_t), size);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -070046}
47
48/* Gets the size field of a TPM command. */
49__attribute__((unused))
Lee Leahy342f8d62017-03-10 15:31:56 -080050static inline int tpm_command_size(const uint8_t *buffer)
51{
Daisuke Nojiri57990972014-07-15 19:47:32 -070052 uint32_t size;
53 from_tpm_uint32(buffer + sizeof(uint16_t), &size);
54 return (int) size;
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -070055}
56
57/* Gets the code field of a TPM command. */
Lee Leahy342f8d62017-03-10 15:31:56 -080058static inline int tpm_command_code(const uint8_t *buffer)
59{
Daisuke Nojiri57990972014-07-15 19:47:32 -070060 uint32_t code;
61 from_tpm_uint32(buffer + sizeof(uint16_t) + sizeof(uint32_t), &code);
62 return code;
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -070063}
64
65/* Gets the return code field of a TPM result. */
Lee Leahy342f8d62017-03-10 15:31:56 -080066static inline int tpm_return_code(const uint8_t *buffer)
67{
Daisuke Nojiri57990972014-07-15 19:47:32 -070068 return tpm_command_code(buffer);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -070069}
70
Jacob Garberfa8f5672020-05-18 13:18:19 -060071/*
72 * Like TlclSendReceive below, but do not retry if NEEDS_SELFTEST or
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -070073 * DOING_SELFTEST errors are returned.
74 */
Lee Leahyb2d834a2017-03-08 16:52:22 -080075static uint32_t tlcl_send_receive_no_retry(const uint8_t *request,
Lee Leahy342f8d62017-03-10 15:31:56 -080076 uint8_t *response, int max_length)
77{
Daisuke Nojiri57990972014-07-15 19:47:32 -070078 uint32_t response_length = max_length;
79 uint32_t result;
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -070080
Daisuke Nojiri57990972014-07-15 19:47:32 -070081 result = tpm_send_receive(request, tpm_command_size(request),
82 response, &response_length);
Lee Leahy36984d82017-03-10 17:56:44 -080083 if (result != 0) {
Daisuke Nojiri57990972014-07-15 19:47:32 -070084 /* Communication with TPM failed, so response is garbage */
85 VBDEBUG("TPM: command 0x%x send/receive failed: 0x%x\n",
86 tpm_command_code(request), result);
87 return result;
88 }
89 /* Otherwise, use the result code from the response */
90 result = tpm_return_code(response);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -070091
Daisuke Nojiri57990972014-07-15 19:47:32 -070092 /* TODO: add paranoia about returned response_length vs. max_length
93 * (and possibly expected length from the response header). See
94 * crosbug.com/17017 */
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -070095
Daisuke Nojiri57990972014-07-15 19:47:32 -070096 VBDEBUG("TPM: command 0x%x returned 0x%x\n",
97 tpm_command_code(request), result);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -070098
Daisuke Nojiri57990972014-07-15 19:47:32 -070099return result;
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700100}
101
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700102/* Sends a TPM command and gets a response. Returns 0 if success or the TPM
Daisuke Nojiri57990972014-07-15 19:47:32 -0700103 * error code if error. Waits for the self test to complete if needed. */
Lee Leahyb2d834a2017-03-08 16:52:22 -0800104uint32_t tlcl_send_receive(const uint8_t *request, uint8_t *response,
Lee Leahy342f8d62017-03-10 15:31:56 -0800105 int max_length)
106{
Daisuke Nojiri57990972014-07-15 19:47:32 -0700107 uint32_t result = tlcl_send_receive_no_retry(request, response,
108 max_length);
109 /* If the command fails because the self test has not completed, try it
110 * again after attempting to ensure that the self test has completed. */
111 if (result == TPM_E_NEEDS_SELFTEST || result == TPM_E_DOING_SELFTEST) {
112 result = tlcl_continue_self_test();
113 if (result != TPM_SUCCESS)
114 return result;
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700115#if defined(TPM_BLOCKING_CONTINUESELFTEST) || defined(VB_RECOVERY_MODE)
Daisuke Nojiri57990972014-07-15 19:47:32 -0700116 /* Retry only once */
117 result = tlcl_send_receive_no_retry(request, response,
Lee Leahye20a3192017-03-09 16:21:34 -0800118 max_length);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700119#else
Daisuke Nojiri57990972014-07-15 19:47:32 -0700120 /* This needs serious testing. The TPM specification says: "iii.
121 * The caller MUST wait for the actions of TPM_ContinueSelfTest
122 * to complete before reissuing the command C1." But, if
123 * ContinueSelfTest is non-blocking, how do we know that the
124 * actions have completed other than trying again? */
125 do {
126 result = tlcl_send_receive_no_retry(request, response,
Lee Leahye20a3192017-03-09 16:21:34 -0800127 max_length);
Daisuke Nojiri57990972014-07-15 19:47:32 -0700128 } while (result == TPM_E_DOING_SELFTEST);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700129#endif
Daisuke Nojiri57990972014-07-15 19:47:32 -0700130 }
131 return result;
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700132}
133
134/* Sends a command and returns the error code. */
Lee Leahy342f8d62017-03-10 15:31:56 -0800135static uint32_t send(const uint8_t *command)
136{
Daisuke Nojiri57990972014-07-15 19:47:32 -0700137 uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
138 return tlcl_send_receive(command, response, sizeof(response));
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700139}
140
141/* Exported functions. */
142
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100143static uint8_t tlcl_init_done;
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800144
Lee Leahy342f8d62017-03-10 15:31:56 -0800145uint32_t tlcl_lib_init(void)
146{
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100147 if (tlcl_init_done)
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800148 return VB2_SUCCESS;
149
Daisuke Nojiri57990972014-07-15 19:47:32 -0700150 if (tis_init())
151 return VB2_ERROR_UNKNOWN;
152 if (tis_open())
153 return VB2_ERROR_UNKNOWN;
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800154
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100155 tlcl_init_done = 1;
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800156
Daisuke Nojiri57990972014-07-15 19:47:32 -0700157 return VB2_SUCCESS;
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700158}
159
Lee Leahy342f8d62017-03-10 15:31:56 -0800160uint32_t tlcl_startup(void)
161{
Daisuke Nojiri57990972014-07-15 19:47:32 -0700162 VBDEBUG("TPM: Startup\n");
163 return send(tpm_startup_cmd.buffer);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700164}
165
Lee Leahy342f8d62017-03-10 15:31:56 -0800166uint32_t tlcl_resume(void)
167{
Lee Leahye20a3192017-03-09 16:21:34 -0800168 VBDEBUG("TPM: Resume\n");
169 return send(tpm_resume_cmd.buffer);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700170}
171
Joel Kitching2e690ee2018-11-15 16:48:53 +0800172uint32_t tlcl_save_state(void)
173{
174 VBDEBUG("TPM: Save state\n");
175 return send(tpm_savestate_cmd.buffer);
176}
177
Daisuke Nojiri57990972014-07-15 19:47:32 -0700178uint32_t tlcl_self_test_full(void)
179{
180 VBDEBUG("TPM: Self test full\n");
181 return send(tpm_selftestfull_cmd.buffer);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700182}
183
Daisuke Nojiri57990972014-07-15 19:47:32 -0700184uint32_t tlcl_continue_self_test(void)
185{
186 uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
187 VBDEBUG("TPM: Continue self test\n");
188 /* Call the No Retry version of SendReceive to avoid recursion. */
189 return tlcl_send_receive_no_retry(tpm_continueselftest_cmd.buffer,
Lee Leahye20a3192017-03-09 16:21:34 -0800190 response, sizeof(response));
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700191}
192
Daisuke Nojiri57990972014-07-15 19:47:32 -0700193uint32_t tlcl_define_space(uint32_t index, uint32_t perm, uint32_t size)
194{
195 struct s_tpm_nv_definespace_cmd cmd;
196 VBDEBUG("TPM: TlclDefineSpace(0x%x, 0x%x, %d)\n", index, perm, size);
197 memcpy(&cmd, &tpm_nv_definespace_cmd, sizeof(cmd));
198 to_tpm_uint32(cmd.buffer + tpm_nv_definespace_cmd.index, index);
199 to_tpm_uint32(cmd.buffer + tpm_nv_definespace_cmd.perm, perm);
200 to_tpm_uint32(cmd.buffer + tpm_nv_definespace_cmd.size, size);
201 return send(cmd.buffer);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700202}
203
Lee Leahyb2d834a2017-03-08 16:52:22 -0800204uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length)
Daisuke Nojiri57990972014-07-15 19:47:32 -0700205{
206 struct s_tpm_nv_write_cmd cmd;
207 uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
208 const int total_length =
209 kTpmRequestHeaderLength + kWriteInfoLength + length;
210
Elyes HAOUAS02d43182021-01-16 17:31:29 +0100211 VBDEBUG("TPM: %s(0x%x, %d)\n", __func__, index, length);
Daisuke Nojiri57990972014-07-15 19:47:32 -0700212 memcpy(&cmd, &tpm_nv_write_cmd, sizeof(cmd));
213 assert(total_length <= TPM_LARGE_ENOUGH_COMMAND_SIZE);
214 set_tpm_command_size(cmd.buffer, total_length);
215
216 to_tpm_uint32(cmd.buffer + tpm_nv_write_cmd.index, index);
217 to_tpm_uint32(cmd.buffer + tpm_nv_write_cmd.length, length);
218 memcpy(cmd.buffer + tpm_nv_write_cmd.data, data, length);
219
220 return tlcl_send_receive(cmd.buffer, response, sizeof(response));
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700221}
222
Lee Leahyb2d834a2017-03-08 16:52:22 -0800223uint32_t tlcl_read(uint32_t index, void *data, uint32_t length)
Daisuke Nojiri57990972014-07-15 19:47:32 -0700224{
225 struct s_tpm_nv_read_cmd cmd;
226 uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
227 uint32_t result_length;
228 uint32_t result;
229
Elyes HAOUAS02d43182021-01-16 17:31:29 +0100230 VBDEBUG("TPM: %s(0x%x, %d)\n", __func__, index, length);
Daisuke Nojiri57990972014-07-15 19:47:32 -0700231 memcpy(&cmd, &tpm_nv_read_cmd, sizeof(cmd));
232 to_tpm_uint32(cmd.buffer + tpm_nv_read_cmd.index, index);
233 to_tpm_uint32(cmd.buffer + tpm_nv_read_cmd.length, length);
234
235 result = tlcl_send_receive(cmd.buffer, response, sizeof(response));
236 if (result == TPM_SUCCESS && length > 0) {
Lee Leahyb2d834a2017-03-08 16:52:22 -0800237 uint8_t *nv_read_cursor = response + kTpmResponseHeaderLength;
Daisuke Nojiri57990972014-07-15 19:47:32 -0700238 from_tpm_uint32(nv_read_cursor, &result_length);
zaolin1356d622018-03-15 00:39:55 +0100239 if (result_length > length)
240 return TPM_E_IOERROR;
Daisuke Nojiri57990972014-07-15 19:47:32 -0700241 nv_read_cursor += sizeof(uint32_t);
242 memcpy(data, nv_read_cursor, result_length);
243 }
244
245 return result;
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700246}
247
Lee Leahy342f8d62017-03-10 15:31:56 -0800248uint32_t tlcl_assert_physical_presence(void)
249{
Daisuke Nojiri57990972014-07-15 19:47:32 -0700250 VBDEBUG("TPM: Asserting physical presence\n");
251 return send(tpm_ppassert_cmd.buffer);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700252}
253
Lee Leahy342f8d62017-03-10 15:31:56 -0800254uint32_t tlcl_physical_presence_cmd_enable(void)
255{
Daisuke Nojiri57990972014-07-15 19:47:32 -0700256 VBDEBUG("TPM: Enable the physical presence command\n");
257 return send(tpm_ppenable_cmd.buffer);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700258}
259
Lee Leahy342f8d62017-03-10 15:31:56 -0800260uint32_t tlcl_finalize_physical_presence(void)
261{
Daisuke Nojiri57990972014-07-15 19:47:32 -0700262 VBDEBUG("TPM: Enable PP cmd, disable HW pp, and set lifetime lock\n");
263 return send(tpm_finalizepp_cmd.buffer);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700264}
265
Lee Leahy342f8d62017-03-10 15:31:56 -0800266uint32_t tlcl_set_nv_locked(void)
267{
Daisuke Nojiri57990972014-07-15 19:47:32 -0700268 VBDEBUG("TPM: Set NV locked\n");
269 return tlcl_define_space(TPM_NV_INDEX_LOCK, 0, 0);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700270}
271
Lee Leahy342f8d62017-03-10 15:31:56 -0800272uint32_t tlcl_force_clear(void)
273{
Daisuke Nojiri57990972014-07-15 19:47:32 -0700274 VBDEBUG("TPM: Force clear\n");
275 return send(tpm_forceclear_cmd.buffer);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700276}
277
Lee Leahy342f8d62017-03-10 15:31:56 -0800278uint32_t tlcl_set_enable(void)
279{
Daisuke Nojiri57990972014-07-15 19:47:32 -0700280 VBDEBUG("TPM: Enabling TPM\n");
281 return send(tpm_physicalenable_cmd.buffer);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700282}
283
Daisuke Nojiri57990972014-07-15 19:47:32 -0700284uint32_t tlcl_set_deactivated(uint8_t flag)
285{
286 struct s_tpm_physicalsetdeactivated_cmd cmd;
287 VBDEBUG("TPM: SetDeactivated(%d)\n", flag);
288 memcpy(&cmd, &tpm_physicalsetdeactivated_cmd, sizeof(cmd));
289 *(cmd.buffer + cmd.deactivated) = flag;
290 return send(cmd.buffer);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700291}
292
Lee Leahyb2d834a2017-03-08 16:52:22 -0800293uint32_t tlcl_get_permanent_flags(TPM_PERMANENT_FLAGS *pflags)
Daisuke Nojiri57990972014-07-15 19:47:32 -0700294{
295 uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
296 uint32_t size;
297 uint32_t result = tlcl_send_receive(tpm_getflags_cmd.buffer, response,
Lee Leahye20a3192017-03-09 16:21:34 -0800298 sizeof(response));
Daisuke Nojiri57990972014-07-15 19:47:32 -0700299 if (result != TPM_SUCCESS)
300 return result;
301 from_tpm_uint32(response + kTpmResponseHeaderLength, &size);
zaolin1356d622018-03-15 00:39:55 +0100302 if (size != sizeof(TPM_PERMANENT_FLAGS))
303 return TPM_E_IOERROR;
Daisuke Nojiri57990972014-07-15 19:47:32 -0700304 memcpy(pflags, response + kTpmResponseHeaderLength + sizeof(size),
305 sizeof(TPM_PERMANENT_FLAGS));
306 return result;
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700307}
308
Lee Leahyb2d834a2017-03-08 16:52:22 -0800309uint32_t tlcl_get_flags(uint8_t *disable, uint8_t *deactivated,
Lee Leahye20a3192017-03-09 16:21:34 -0800310 uint8_t *nvlocked)
Daisuke Nojiri57990972014-07-15 19:47:32 -0700311{
312 TPM_PERMANENT_FLAGS pflags;
313 uint32_t result = tlcl_get_permanent_flags(&pflags);
314 if (result == TPM_SUCCESS) {
315 if (disable)
316 *disable = pflags.disable;
317 if (deactivated)
318 *deactivated = pflags.deactivated;
319 if (nvlocked)
320 *nvlocked = pflags.nvLocked;
321 VBDEBUG("TPM: flags disable=%d, deactivated=%d, nvlocked=%d\n",
322 pflags.disable, pflags.deactivated, pflags.nvLocked);
323 }
324 return result;
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700325}
326
Daisuke Nojiri57990972014-07-15 19:47:32 -0700327uint32_t tlcl_set_global_lock(void)
328{
329 uint32_t x;
330 VBDEBUG("TPM: Set global lock\n");
Lee Leahyb2d834a2017-03-08 16:52:22 -0800331 return tlcl_write(TPM_NV_INDEX0, (uint8_t *) &x, 0);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700332}
333
Lee Leahyb2d834a2017-03-08 16:52:22 -0800334uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
Lee Leahye20a3192017-03-09 16:21:34 -0800335 uint8_t *out_digest)
Daisuke Nojiri57990972014-07-15 19:47:32 -0700336{
337 struct s_tpm_extend_cmd cmd;
338 uint8_t response[kTpmResponseHeaderLength + kPcrDigestLength];
339 uint32_t result;
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700340
Daisuke Nojiri57990972014-07-15 19:47:32 -0700341 memcpy(&cmd, &tpm_extend_cmd, sizeof(cmd));
342 to_tpm_uint32(cmd.buffer + tpm_extend_cmd.pcrNum, pcr_num);
343 memcpy(cmd.buffer + cmd.inDigest, in_digest, kPcrDigestLength);
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700344
Daisuke Nojiri57990972014-07-15 19:47:32 -0700345 result = tlcl_send_receive(cmd.buffer, response, sizeof(response));
346 if (result != TPM_SUCCESS)
347 return result;
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700348
Julius Werner76e33032015-01-30 18:45:27 -0800349 if (out_digest)
350 memcpy(out_digest, response + kTpmResponseHeaderLength,
351 kPcrDigestLength);
Daisuke Nojiri57990972014-07-15 19:47:32 -0700352 return result;
Daisuke Nojiriefb5cde2014-07-02 08:37:23 -0700353}
Daisuke Nojirid9f26ed2020-04-21 15:13:07 -0700354
355uint32_t tlcl_get_permissions(uint32_t index, uint32_t *permissions)
356{
357 struct s_tpm_getpermissions_cmd cmd;
358 uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
359 uint8_t *nvdata;
360 uint32_t result;
361 uint32_t size;
362
363 memcpy(&cmd, &tpm_getpermissions_cmd, sizeof(cmd));
364 to_tpm_uint32(cmd.buffer + tpm_getpermissions_cmd.index, index);
365 result = tlcl_send_receive(cmd.buffer, response, sizeof(response));
366 if (result != TPM_SUCCESS)
367 return result;
368
369 nvdata = response + kTpmResponseHeaderLength + sizeof(size);
370 from_tpm_uint32(nvdata + kNvDataPublicPermissionsOffset, permissions);
371 return result;
372}