blob: 60a18ca50400404b3a16bdbc431898f7fb211186 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Che-liang Chiou8732b072013-02-28 09:34:57 +00002/*
3 * Copyright (c) 2013 The Chromium OS Authors.
Reinhard Pfaube6c1522013-06-26 15:55:13 +02004 * Coypright (c) 2013 Guntermann & Drunck GmbH
Che-liang Chiou8732b072013-02-28 09:34:57 +00005 */
6
Simon Glass6e64ec12018-10-01 12:22:29 -06007#define LOG_CATEGORY UCLASS_TPM
8
Che-liang Chiou8732b072013-02-28 09:34:57 +00009#include <common.h>
Simon Glassc8a8c512015-08-22 18:31:32 -060010#include <dm.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060011#include <log.h>
Che-liang Chiou8732b072013-02-28 09:34:57 +000012#include <asm/unaligned.h>
Simon Glassc8a8c512015-08-22 18:31:32 -060013#include <u-boot/sha1.h>
Miquel Raynald677bfe2018-05-15 11:57:06 +020014#include <tpm-common.h>
15#include <tpm-v1.h>
16#include "tpm-utils.h"
Che-liang Chiou8732b072013-02-28 09:34:57 +000017
Reinhard Pfaube6c1522013-06-26 15:55:13 +020018#ifdef CONFIG_TPM_AUTH_SESSIONS
19
20#ifndef CONFIG_SHA1
21#error "TPM_AUTH_SESSIONS require SHA1 to be configured, too"
22#endif /* !CONFIG_SHA1 */
23
24struct session_data {
25 int valid;
Miquel Raynalb9804e52018-05-15 11:56:59 +020026 u32 handle;
27 u8 nonce_even[DIGEST_LENGTH];
28 u8 nonce_odd[DIGEST_LENGTH];
Reinhard Pfaube6c1522013-06-26 15:55:13 +020029};
30
31static struct session_data oiap_session = {0, };
32
33#endif /* CONFIG_TPM_AUTH_SESSIONS */
34
Simon Glassd6a885f2021-02-06 14:23:36 -070035u32 tpm1_startup(struct udevice *dev, enum tpm_startup_type mode)
Che-liang Chiou8732b072013-02-28 09:34:57 +000036{
Miquel Raynalb9804e52018-05-15 11:56:59 +020037 const u8 command[12] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +000038 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
39 };
40 const size_t mode_offset = 10;
Miquel Raynalb9804e52018-05-15 11:56:59 +020041 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +000042
43 if (pack_byte_string(buf, sizeof(buf), "sw",
Miquel Raynalc6179182018-05-15 11:57:00 +020044 0, command, sizeof(command),
45 mode_offset, mode))
Che-liang Chiou8732b072013-02-28 09:34:57 +000046 return TPM_LIB_ERROR;
47
Simon Glassabdc7b82018-11-18 14:22:27 -070048 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiou8732b072013-02-28 09:34:57 +000049}
50
Simon Glassd6a885f2021-02-06 14:23:36 -070051u32 tpm1_resume(struct udevice *dev)
Simon Glass6e64ec12018-10-01 12:22:29 -060052{
Simon Glassd6a885f2021-02-06 14:23:36 -070053 return tpm1_startup(dev, TPM_ST_STATE);
Simon Glass6e64ec12018-10-01 12:22:29 -060054}
55
Simon Glassd6a885f2021-02-06 14:23:36 -070056u32 tpm1_self_test_full(struct udevice *dev)
Che-liang Chiou8732b072013-02-28 09:34:57 +000057{
Miquel Raynalb9804e52018-05-15 11:56:59 +020058 const u8 command[10] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +000059 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
60 };
Simon Glassabdc7b82018-11-18 14:22:27 -070061 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiou8732b072013-02-28 09:34:57 +000062}
63
Simon Glassd6a885f2021-02-06 14:23:36 -070064u32 tpm1_continue_self_test(struct udevice *dev)
Che-liang Chiou8732b072013-02-28 09:34:57 +000065{
Miquel Raynalb9804e52018-05-15 11:56:59 +020066 const u8 command[10] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +000067 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
68 };
Simon Glassabdc7b82018-11-18 14:22:27 -070069 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiou8732b072013-02-28 09:34:57 +000070}
71
Simon Glassa11be4c2023-02-21 06:24:52 -070072u32 tpm1_auto_start(struct udevice *dev)
73{
74 u32 rc;
75
76 rc = tpm1_startup(dev, TPM_ST_CLEAR);
77 /* continue on if the TPM is already inited */
78 if (rc && rc != TPM_INVALID_POSTINIT)
79 return rc;
80
81 rc = tpm1_self_test_full(dev);
82
83 return rc;
84}
85
Simon Glassd6a885f2021-02-06 14:23:36 -070086u32 tpm1_clear_and_reenable(struct udevice *dev)
Simon Glass6e64ec12018-10-01 12:22:29 -060087{
88 u32 ret;
89
90 log_info("TPM: Clear and re-enable\n");
Simon Glassd6a885f2021-02-06 14:23:36 -070091 ret = tpm1_force_clear(dev);
Simon Glass6e64ec12018-10-01 12:22:29 -060092 if (ret != TPM_SUCCESS) {
93 log_err("Can't initiate a force clear\n");
94 return ret;
95 }
96
Simon Glassd6a885f2021-02-06 14:23:36 -070097 ret = tpm1_physical_enable(dev);
98 if (ret != TPM_SUCCESS) {
99 log_err("TPM: Can't set enabled state\n");
100 return ret;
101 }
Simon Glass6e64ec12018-10-01 12:22:29 -0600102
Simon Glassd6a885f2021-02-06 14:23:36 -0700103 ret = tpm1_physical_set_deactivated(dev, 0);
104 if (ret != TPM_SUCCESS) {
105 log_err("TPM: Can't set deactivated state\n");
106 return ret;
Simon Glass6e64ec12018-10-01 12:22:29 -0600107 }
Simon Glass6e64ec12018-10-01 12:22:29 -0600108
109 return TPM_SUCCESS;
110}
111
Simon Glassd6a885f2021-02-06 14:23:36 -0700112u32 tpm1_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000113{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200114 const u8 command[101] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000115 0x0, 0xc1, /* TPM_TAG */
116 0x0, 0x0, 0x0, 0x65, /* parameter size */
117 0x0, 0x0, 0x0, 0xcc, /* TPM_COMMAND_CODE */
118 /* TPM_NV_DATA_PUBLIC->... */
119 0x0, 0x18, /* ...->TPM_STRUCTURE_TAG */
120 0, 0, 0, 0, /* ...->TPM_NV_INDEX */
121 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
122 0x0, 0x3,
123 0, 0, 0,
124 0x1f,
125 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
126 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
127 0x0, 0x3,
128 0, 0, 0,
129 0x1f,
130 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
131 /* TPM_NV_ATTRIBUTES->... */
132 0x0, 0x17, /* ...->TPM_STRUCTURE_TAG */
133 0, 0, 0, 0, /* ...->attributes */
134 /* End of TPM_NV_ATTRIBUTES */
135 0, /* bReadSTClear */
136 0, /* bWriteSTClear */
137 0, /* bWriteDefine */
138 0, 0, 0, 0, /* size */
139 };
140 const size_t index_offset = 12;
141 const size_t perm_offset = 70;
142 const size_t size_offset = 77;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200143 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000144
145 if (pack_byte_string(buf, sizeof(buf), "sddd",
Miquel Raynalc6179182018-05-15 11:57:00 +0200146 0, command, sizeof(command),
147 index_offset, index,
148 perm_offset, perm,
149 size_offset, size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000150 return TPM_LIB_ERROR;
151
Simon Glassabdc7b82018-11-18 14:22:27 -0700152 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000153}
154
Simon Glassd6a885f2021-02-06 14:23:36 -0700155u32 tpm1_nv_set_locked(struct udevice *dev)
Simon Glass6e64ec12018-10-01 12:22:29 -0600156{
Simon Glassd6a885f2021-02-06 14:23:36 -0700157 return tpm1_nv_define_space(dev, TPM_NV_INDEX_LOCK, 0, 0);
Simon Glass6e64ec12018-10-01 12:22:29 -0600158}
159
Simon Glassd6a885f2021-02-06 14:23:36 -0700160u32 tpm1_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000161{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200162 const u8 command[22] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000163 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
164 };
165 const size_t index_offset = 10;
166 const size_t length_offset = 18;
167 const size_t data_size_offset = 10;
168 const size_t data_offset = 14;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200169 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000170 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200171 u32 data_size;
172 u32 err;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000173
174 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynalc6179182018-05-15 11:57:00 +0200175 0, command, sizeof(command),
176 index_offset, index,
177 length_offset, count))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000178 return TPM_LIB_ERROR;
Simon Glassabdc7b82018-11-18 14:22:27 -0700179 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000180 if (err)
181 return err;
182 if (unpack_byte_string(response, response_length, "d",
Miquel Raynalc6179182018-05-15 11:57:00 +0200183 data_size_offset, &data_size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000184 return TPM_LIB_ERROR;
185 if (data_size > count)
186 return TPM_LIB_ERROR;
187 if (unpack_byte_string(response, response_length, "s",
Miquel Raynalc6179182018-05-15 11:57:00 +0200188 data_offset, data, data_size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000189 return TPM_LIB_ERROR;
190
191 return 0;
192}
193
Simon Glassd6a885f2021-02-06 14:23:36 -0700194u32 tpm1_nv_write_value(struct udevice *dev, u32 index, const void *data,
195 u32 length)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000196{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200197 const u8 command[256] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000198 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
199 };
200 const size_t command_size_offset = 2;
201 const size_t index_offset = 10;
202 const size_t length_offset = 18;
203 const size_t data_offset = 22;
204 const size_t write_info_size = 12;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200205 const u32 total_length =
Che-liang Chiou8732b072013-02-28 09:34:57 +0000206 TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200207 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000208 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200209 u32 err;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000210
211 if (pack_byte_string(buf, sizeof(buf), "sddds",
Miquel Raynalc6179182018-05-15 11:57:00 +0200212 0, command, sizeof(command),
213 command_size_offset, total_length,
214 index_offset, index,
215 length_offset, length,
216 data_offset, data, length))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000217 return TPM_LIB_ERROR;
Simon Glassabdc7b82018-11-18 14:22:27 -0700218 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000219 if (err)
220 return err;
221
222 return 0;
223}
224
Simon Glassd6a885f2021-02-06 14:23:36 -0700225u32 tpm1_extend(struct udevice *dev, u32 index, const void *in_digest,
226 void *out_digest)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000227{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200228 const u8 command[34] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000229 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
230 };
231 const size_t index_offset = 10;
232 const size_t in_digest_offset = 14;
233 const size_t out_digest_offset = 10;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200234 u8 buf[COMMAND_BUFFER_SIZE];
235 u8 response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000236 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200237 u32 err;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000238
239 if (pack_byte_string(buf, sizeof(buf), "sds",
Miquel Raynalc6179182018-05-15 11:57:00 +0200240 0, command, sizeof(command),
241 index_offset, index,
242 in_digest_offset, in_digest,
243 PCR_DIGEST_LENGTH))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000244 return TPM_LIB_ERROR;
Simon Glassabdc7b82018-11-18 14:22:27 -0700245 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000246 if (err)
247 return err;
248
249 if (unpack_byte_string(response, response_length, "s",
Miquel Raynalc6179182018-05-15 11:57:00 +0200250 out_digest_offset, out_digest,
251 PCR_DIGEST_LENGTH))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000252 return TPM_LIB_ERROR;
253
254 return 0;
255}
256
Simon Glassd6a885f2021-02-06 14:23:36 -0700257u32 tpm1_pcr_read(struct udevice *dev, u32 index, void *data, size_t count)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000258{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200259 const u8 command[14] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000260 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
261 };
262 const size_t index_offset = 10;
263 const size_t out_digest_offset = 10;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200264 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000265 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200266 u32 err;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000267
268 if (count < PCR_DIGEST_LENGTH)
269 return TPM_LIB_ERROR;
270
271 if (pack_byte_string(buf, sizeof(buf), "sd",
Miquel Raynalc6179182018-05-15 11:57:00 +0200272 0, command, sizeof(command),
273 index_offset, index))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000274 return TPM_LIB_ERROR;
Simon Glassabdc7b82018-11-18 14:22:27 -0700275 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000276 if (err)
277 return err;
278 if (unpack_byte_string(response, response_length, "s",
Miquel Raynalc6179182018-05-15 11:57:00 +0200279 out_digest_offset, data, PCR_DIGEST_LENGTH))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000280 return TPM_LIB_ERROR;
281
282 return 0;
283}
284
Simon Glassd6a885f2021-02-06 14:23:36 -0700285u32 tpm1_tsc_physical_presence(struct udevice *dev, u16 presence)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000286{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200287 const u8 command[12] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000288 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
289 };
290 const size_t presence_offset = 10;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200291 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000292
293 if (pack_byte_string(buf, sizeof(buf), "sw",
Miquel Raynalc6179182018-05-15 11:57:00 +0200294 0, command, sizeof(command),
295 presence_offset, presence))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000296 return TPM_LIB_ERROR;
297
Simon Glassabdc7b82018-11-18 14:22:27 -0700298 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000299}
300
Simon Glassd6a885f2021-02-06 14:23:36 -0700301u32 tpm1_finalise_physical_presence(struct udevice *dev)
Simon Glass6e64ec12018-10-01 12:22:29 -0600302{
303 const u8 command[12] = {
304 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x2, 0xa0,
305 };
306
Simon Glassabdc7b82018-11-18 14:22:27 -0700307 return tpm_sendrecv_command(dev, command, NULL, NULL);
Simon Glass6e64ec12018-10-01 12:22:29 -0600308}
309
Simon Glassd6a885f2021-02-06 14:23:36 -0700310u32 tpm1_read_pubek(struct udevice *dev, void *data, size_t count)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000311{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200312 const u8 command[30] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000313 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
314 };
315 const size_t response_size_offset = 2;
316 const size_t data_offset = 10;
317 const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200318 u8 response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000319 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200320 u32 data_size;
321 u32 err;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000322
Simon Glassabdc7b82018-11-18 14:22:27 -0700323 err = tpm_sendrecv_command(dev, command, response, &response_length);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000324 if (err)
325 return err;
326 if (unpack_byte_string(response, response_length, "d",
Miquel Raynalc6179182018-05-15 11:57:00 +0200327 response_size_offset, &data_size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000328 return TPM_LIB_ERROR;
329 if (data_size < header_and_checksum_size)
330 return TPM_LIB_ERROR;
331 data_size -= header_and_checksum_size;
332 if (data_size > count)
333 return TPM_LIB_ERROR;
334 if (unpack_byte_string(response, response_length, "s",
Miquel Raynalc6179182018-05-15 11:57:00 +0200335 data_offset, data, data_size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000336 return TPM_LIB_ERROR;
337
338 return 0;
339}
340
Simon Glassd6a885f2021-02-06 14:23:36 -0700341u32 tpm1_force_clear(struct udevice *dev)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000342{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200343 const u8 command[10] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000344 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
345 };
346
Simon Glassabdc7b82018-11-18 14:22:27 -0700347 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000348}
349
Simon Glassd6a885f2021-02-06 14:23:36 -0700350u32 tpm1_physical_enable(struct udevice *dev)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000351{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200352 const u8 command[10] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000353 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
354 };
355
Simon Glassabdc7b82018-11-18 14:22:27 -0700356 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000357}
358
Simon Glassd6a885f2021-02-06 14:23:36 -0700359u32 tpm1_physical_disable(struct udevice *dev)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000360{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200361 const u8 command[10] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000362 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
363 };
364
Simon Glassabdc7b82018-11-18 14:22:27 -0700365 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000366}
367
Simon Glassd6a885f2021-02-06 14:23:36 -0700368u32 tpm1_physical_set_deactivated(struct udevice *dev, u8 state)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000369{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200370 const u8 command[11] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000371 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
372 };
373 const size_t state_offset = 10;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200374 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000375
376 if (pack_byte_string(buf, sizeof(buf), "sb",
Miquel Raynalc6179182018-05-15 11:57:00 +0200377 0, command, sizeof(command),
378 state_offset, state))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000379 return TPM_LIB_ERROR;
380
Simon Glassabdc7b82018-11-18 14:22:27 -0700381 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000382}
383
Simon Glassd6a885f2021-02-06 14:23:36 -0700384u32 tpm1_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap,
385 void *cap, size_t count)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000386{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200387 const u8 command[22] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000388 0x0, 0xc1, /* TPM_TAG */
389 0x0, 0x0, 0x0, 0x16, /* parameter size */
390 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
391 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */
392 0x0, 0x0, 0x0, 0x4, /* subcap size */
393 0x0, 0x0, 0x0, 0x0, /* subcap value */
394 };
395 const size_t cap_area_offset = 10;
396 const size_t sub_cap_offset = 18;
397 const size_t cap_offset = 14;
398 const size_t cap_size_offset = 10;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200399 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000400 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200401 u32 cap_size;
402 u32 err;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000403
404 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynalc6179182018-05-15 11:57:00 +0200405 0, command, sizeof(command),
406 cap_area_offset, cap_area,
407 sub_cap_offset, sub_cap))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000408 return TPM_LIB_ERROR;
Simon Glassabdc7b82018-11-18 14:22:27 -0700409 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiou8732b072013-02-28 09:34:57 +0000410 if (err)
411 return err;
412 if (unpack_byte_string(response, response_length, "d",
Miquel Raynalc6179182018-05-15 11:57:00 +0200413 cap_size_offset, &cap_size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000414 return TPM_LIB_ERROR;
415 if (cap_size > response_length || cap_size > count)
416 return TPM_LIB_ERROR;
417 if (unpack_byte_string(response, response_length, "s",
Miquel Raynalc6179182018-05-15 11:57:00 +0200418 cap_offset, cap, cap_size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000419 return TPM_LIB_ERROR;
420
421 return 0;
422}
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200423
Simon Glassd6a885f2021-02-06 14:23:36 -0700424u32 tpm1_get_permanent_flags(struct udevice *dev,
425 struct tpm_permanent_flags *pflags)
Simon Glass2132f972015-08-22 18:31:41 -0600426{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200427 const u8 command[22] = {
Simon Glass2132f972015-08-22 18:31:41 -0600428 0x0, 0xc1, /* TPM_TAG */
429 0x0, 0x0, 0x0, 0x16, /* parameter size */
430 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
431 0x0, 0x0, 0x0, 0x4, /* TPM_CAP_FLAG_PERM */
432 0x0, 0x0, 0x0, 0x4, /* subcap size */
433 0x0, 0x0, 0x1, 0x8, /* subcap value */
434 };
André Draszike8155df2017-10-03 16:55:51 +0100435 const size_t data_size_offset = TPM_HEADER_SIZE;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200436 const size_t data_offset = TPM_HEADER_SIZE + sizeof(u32);
437 u8 response[COMMAND_BUFFER_SIZE];
Simon Glass2132f972015-08-22 18:31:41 -0600438 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200439 u32 err;
440 u32 data_size;
Simon Glass2132f972015-08-22 18:31:41 -0600441
Simon Glassabdc7b82018-11-18 14:22:27 -0700442 err = tpm_sendrecv_command(dev, command, response, &response_length);
Simon Glass2132f972015-08-22 18:31:41 -0600443 if (err)
444 return err;
André Draszike8155df2017-10-03 16:55:51 +0100445 if (unpack_byte_string(response, response_length, "d",
Simon Glass6e64ec12018-10-01 12:22:29 -0600446 data_size_offset, &data_size)) {
447 log_err("Cannot unpack data size\n");
André Draszike8155df2017-10-03 16:55:51 +0100448 return TPM_LIB_ERROR;
Simon Glass6e64ec12018-10-01 12:22:29 -0600449 }
450 if (data_size < sizeof(*pflags)) {
451 log_err("Data size too small\n");
André Draszike8155df2017-10-03 16:55:51 +0100452 return TPM_LIB_ERROR;
Simon Glass6e64ec12018-10-01 12:22:29 -0600453 }
André Draszike8155df2017-10-03 16:55:51 +0100454 if (unpack_byte_string(response, response_length, "s",
Simon Glass6e64ec12018-10-01 12:22:29 -0600455 data_offset, pflags, sizeof(*pflags))) {
456 log_err("Cannot unpack pflags\n");
André Draszike8155df2017-10-03 16:55:51 +0100457 return TPM_LIB_ERROR;
Simon Glass6e64ec12018-10-01 12:22:29 -0600458 }
Simon Glass2132f972015-08-22 18:31:41 -0600459
460 return 0;
461}
462
Simon Glassd6a885f2021-02-06 14:23:36 -0700463u32 tpm1_get_permissions(struct udevice *dev, u32 index, u32 *perm)
Simon Glass2132f972015-08-22 18:31:41 -0600464{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200465 const u8 command[22] = {
Simon Glass2132f972015-08-22 18:31:41 -0600466 0x0, 0xc1, /* TPM_TAG */
467 0x0, 0x0, 0x0, 0x16, /* parameter size */
468 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
469 0x0, 0x0, 0x0, 0x11,
470 0x0, 0x0, 0x0, 0x4,
471 };
472 const size_t index_offset = 18;
Simon Glassa0f38042022-08-30 21:05:33 -0600473 const size_t perm_offset = 74;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200474 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Simon Glass2132f972015-08-22 18:31:41 -0600475 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200476 u32 err;
Simon Glass2132f972015-08-22 18:31:41 -0600477
Simon Glassa0f38042022-08-30 21:05:33 -0600478 if (pack_byte_string(buf, sizeof(buf), "sd",
479 0, command, sizeof(command),
Simon Glass2132f972015-08-22 18:31:41 -0600480 index_offset, index))
481 return TPM_LIB_ERROR;
Simon Glassabdc7b82018-11-18 14:22:27 -0700482 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Simon Glass2132f972015-08-22 18:31:41 -0600483 if (err)
484 return err;
485 if (unpack_byte_string(response, response_length, "d",
486 perm_offset, perm))
487 return TPM_LIB_ERROR;
488
489 return 0;
490}
491
Mario Six7690be32017-01-11 16:00:50 +0100492#ifdef CONFIG_TPM_FLUSH_RESOURCES
Simon Glassd6a885f2021-02-06 14:23:36 -0700493u32 tpm1_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type)
Mario Six7690be32017-01-11 16:00:50 +0100494{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200495 const u8 command[18] = {
Mario Six7690be32017-01-11 16:00:50 +0100496 0x00, 0xc1, /* TPM_TAG */
497 0x00, 0x00, 0x00, 0x12, /* parameter size */
498 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
499 0x00, 0x00, 0x00, 0x00, /* key handle */
500 0x00, 0x00, 0x00, 0x00, /* resource type */
501 };
502 const size_t key_handle_offset = 10;
503 const size_t resource_type_offset = 14;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200504 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Mario Six7690be32017-01-11 16:00:50 +0100505 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200506 u32 err;
Mario Six7690be32017-01-11 16:00:50 +0100507
508 if (pack_byte_string(buf, sizeof(buf), "sdd",
509 0, command, sizeof(command),
510 key_handle_offset, key_handle,
511 resource_type_offset, resource_type))
512 return TPM_LIB_ERROR;
513
Simon Glassabdc7b82018-11-18 14:22:27 -0700514 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Mario Six7690be32017-01-11 16:00:50 +0100515 if (err)
516 return err;
517 return 0;
518}
519#endif /* CONFIG_TPM_FLUSH_RESOURCES */
520
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200521#ifdef CONFIG_TPM_AUTH_SESSIONS
522
523/**
524 * Fill an authentication block in a request.
525 * This func can create the first as well as the second auth block (for
526 * double authorized commands).
527 *
528 * @param request pointer to the request (w/ uninitialised auth data)
529 * @param request_len0 length of the request without auth data
530 * @param handles_len length of the handles area in request
531 * @param auth_session pointer to the (valid) auth session to be used
532 * @param request_auth pointer to the auth block of the request to be filled
533 * @param auth authentication data (HMAC key)
534 */
Miquel Raynalb9804e52018-05-15 11:56:59 +0200535static u32 create_request_auth(const void *request, size_t request_len0,
536 size_t handles_len,
537 struct session_data *auth_session,
538 void *request_auth, const void *auth)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200539{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200540 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200541 sha1_context hash_ctx;
542 const size_t command_code_offset = 6;
543 const size_t auth_nonce_odd_offset = 4;
544 const size_t auth_continue_offset = 24;
545 const size_t auth_auth_offset = 25;
546
547 if (!auth_session || !auth_session->valid)
548 return TPM_LIB_ERROR;
549
550 sha1_starts(&hash_ctx);
551 sha1_update(&hash_ctx, request + command_code_offset, 4);
552 if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
553 sha1_update(&hash_ctx,
554 request + TPM_REQUEST_HEADER_LENGTH + handles_len,
555 request_len0 - TPM_REQUEST_HEADER_LENGTH
556 - handles_len);
557 sha1_finish(&hash_ctx, hmac_data);
558
559 sha1_starts(&hash_ctx);
560 sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
561 sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
562 sha1_finish(&hash_ctx, auth_session->nonce_odd);
563
564 if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
565 0, auth_session->handle,
566 auth_nonce_odd_offset, auth_session->nonce_odd,
567 DIGEST_LENGTH,
568 auth_continue_offset, 1))
569 return TPM_LIB_ERROR;
570 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
571 DIGEST_LENGTH,
572 auth_session->nonce_even,
573 DIGEST_LENGTH,
574 2 * DIGEST_LENGTH,
575 request_auth + auth_nonce_odd_offset,
576 DIGEST_LENGTH + 1))
577 return TPM_LIB_ERROR;
578 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
579 request_auth + auth_auth_offset);
580
581 return TPM_SUCCESS;
582}
583
584/**
585 * Verify an authentication block in a response.
586 * Since this func updates the nonce_even in the session data it has to be
587 * called when receiving a succesfull AUTH response.
588 * This func can verify the first as well as the second auth block (for
589 * double authorized commands).
590 *
591 * @param command_code command code of the request
592 * @param response pointer to the request (w/ uninitialised auth data)
593 * @param handles_len length of the handles area in response
594 * @param auth_session pointer to the (valid) auth session to be used
595 * @param response_auth pointer to the auth block of the response to be verified
596 * @param auth authentication data (HMAC key)
597 */
Miquel Raynalb9804e52018-05-15 11:56:59 +0200598static u32 verify_response_auth(u32 command_code, const void *response,
599 size_t response_len0, size_t handles_len,
600 struct session_data *auth_session,
601 const void *response_auth, const void *auth)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200602{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200603 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
604 u8 computed_auth[DIGEST_LENGTH];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200605 sha1_context hash_ctx;
606 const size_t return_code_offset = 6;
607 const size_t auth_continue_offset = 20;
608 const size_t auth_auth_offset = 21;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200609 u8 auth_continue;
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200610
611 if (!auth_session || !auth_session->valid)
612 return TPM_AUTHFAIL;
613 if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
614 0, command_code))
615 return TPM_LIB_ERROR;
616 if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
617 return TPM_LIB_ERROR;
618
619 sha1_starts(&hash_ctx);
620 sha1_update(&hash_ctx, response + return_code_offset, 4);
621 sha1_update(&hash_ctx, hmac_data, 4);
622 if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
623 sha1_update(&hash_ctx,
624 response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
625 response_len0 - TPM_RESPONSE_HEADER_LENGTH
626 - handles_len);
627 sha1_finish(&hash_ctx, hmac_data);
628
629 memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200630 auth_continue = ((u8 *)response_auth)[auth_continue_offset];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200631 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
632 DIGEST_LENGTH,
633 response_auth,
634 DIGEST_LENGTH,
635 2 * DIGEST_LENGTH,
636 auth_session->nonce_odd,
637 DIGEST_LENGTH,
638 3 * DIGEST_LENGTH,
639 auth_continue))
640 return TPM_LIB_ERROR;
641
642 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
643 computed_auth);
644
645 if (memcmp(computed_auth, response_auth + auth_auth_offset,
646 DIGEST_LENGTH))
647 return TPM_AUTHFAIL;
648
649 return TPM_SUCCESS;
650}
651
Simon Glassd6a885f2021-02-06 14:23:36 -0700652u32 tpm1_terminate_auth_session(struct udevice *dev, u32 auth_handle)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200653{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200654 const u8 command[18] = {
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200655 0x00, 0xc1, /* TPM_TAG */
656 0x00, 0x00, 0x00, 0x00, /* parameter size */
657 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
658 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
Miquel Raynal52da18a2018-05-15 11:57:02 +0200659 0x00, 0x00, 0x00, 0x02, /* TPM_RESOURCE_TYPE */
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200660 };
661 const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200662 u8 request[COMMAND_BUFFER_SIZE];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200663
664 if (pack_byte_string(request, sizeof(request), "sd",
665 0, command, sizeof(command),
666 req_handle_offset, auth_handle))
667 return TPM_LIB_ERROR;
668 if (oiap_session.valid && oiap_session.handle == auth_handle)
669 oiap_session.valid = 0;
670
Simon Glassabdc7b82018-11-18 14:22:27 -0700671 return tpm_sendrecv_command(dev, request, NULL, NULL);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200672}
673
Simon Glassd6a885f2021-02-06 14:23:36 -0700674u32 tpm1_end_oiap(struct udevice *dev)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200675{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200676 u32 err = TPM_SUCCESS;
Miquel Raynal96cc4e32018-05-15 11:57:03 +0200677
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200678 if (oiap_session.valid)
Simon Glassd6a885f2021-02-06 14:23:36 -0700679 err = tpm1_terminate_auth_session(dev, oiap_session.handle);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200680 return err;
681}
682
Simon Glassd6a885f2021-02-06 14:23:36 -0700683u32 tpm1_oiap(struct udevice *dev, u32 *auth_handle)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200684{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200685 const u8 command[10] = {
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200686 0x00, 0xc1, /* TPM_TAG */
687 0x00, 0x00, 0x00, 0x0a, /* parameter size */
688 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
689 };
690 const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
691 const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200692 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200693 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200694 u32 err;
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200695
696 if (oiap_session.valid)
Simon Glassd6a885f2021-02-06 14:23:36 -0700697 tpm1_terminate_auth_session(dev, oiap_session.handle);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200698
Simon Glassabdc7b82018-11-18 14:22:27 -0700699 err = tpm_sendrecv_command(dev, command, response, &response_length);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200700 if (err)
701 return err;
702 if (unpack_byte_string(response, response_length, "ds",
703 res_auth_handle_offset, &oiap_session.handle,
704 res_nonce_even_offset, &oiap_session.nonce_even,
Miquel Raynalb9804e52018-05-15 11:56:59 +0200705 (u32)DIGEST_LENGTH))
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200706 return TPM_LIB_ERROR;
707 oiap_session.valid = 1;
708 if (auth_handle)
709 *auth_handle = oiap_session.handle;
710 return 0;
711}
712
Simon Glassd6a885f2021-02-06 14:23:36 -0700713u32 tpm1_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key,
714 size_t key_length, const void *parent_key_usage_auth,
715 u32 *key_handle)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200716{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200717 const u8 command[14] = {
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200718 0x00, 0xc2, /* TPM_TAG */
719 0x00, 0x00, 0x00, 0x00, /* parameter size */
720 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
721 0x00, 0x00, 0x00, 0x00, /* parent handle */
722 };
723 const size_t req_size_offset = 2;
724 const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
725 const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
726 const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200727 u8 request[sizeof(command) + TPM_KEY12_MAX_LENGTH +
728 TPM_REQUEST_AUTH_LENGTH];
729 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200730 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200731 u32 err;
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200732
733 if (!oiap_session.valid) {
Simon Glassd6a885f2021-02-06 14:23:36 -0700734 err = tpm1_oiap(dev, NULL);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200735 if (err)
736 return err;
737 }
738 if (pack_byte_string(request, sizeof(request), "sdds",
739 0, command, sizeof(command),
740 req_size_offset,
741 sizeof(command) + key_length
742 + TPM_REQUEST_AUTH_LENGTH,
743 req_parent_handle_offset, parent_handle,
744 req_key_offset, key, key_length
745 ))
746 return TPM_LIB_ERROR;
747
748 err = create_request_auth(request, sizeof(command) + key_length, 4,
Miquel Raynalc6179182018-05-15 11:57:00 +0200749 &oiap_session,
750 request + sizeof(command) + key_length,
751 parent_key_usage_auth);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200752 if (err)
753 return err;
Simon Glassabdc7b82018-11-18 14:22:27 -0700754 err = tpm_sendrecv_command(dev, request, response, &response_length);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200755 if (err) {
756 if (err == TPM_AUTHFAIL)
757 oiap_session.valid = 0;
758 return err;
759 }
760
761 err = verify_response_auth(0x00000041, response,
Miquel Raynalc6179182018-05-15 11:57:00 +0200762 response_length - TPM_RESPONSE_AUTH_LENGTH,
763 4, &oiap_session,
764 response + response_length -
765 TPM_RESPONSE_AUTH_LENGTH,
766 parent_key_usage_auth);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200767 if (err)
768 return err;
769
770 if (key_handle) {
771 if (unpack_byte_string(response, response_length, "d",
772 res_handle_offset, key_handle))
773 return TPM_LIB_ERROR;
774 }
775
776 return 0;
777}
778
Simon Glassd6a885f2021-02-06 14:23:36 -0700779u32 tpm1_get_pub_key_oiap(struct udevice *dev, u32 key_handle,
780 const void *usage_auth, void *pubkey,
781 size_t *pubkey_len)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200782{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200783 const u8 command[14] = {
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200784 0x00, 0xc2, /* TPM_TAG */
785 0x00, 0x00, 0x00, 0x00, /* parameter size */
786 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
787 0x00, 0x00, 0x00, 0x00, /* key handle */
788 };
789 const size_t req_size_offset = 2;
790 const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
791 const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200792 u8 request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
793 u8 response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH +
794 TPM_RESPONSE_AUTH_LENGTH];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200795 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200796 u32 err;
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200797
798 if (!oiap_session.valid) {
Simon Glassd6a885f2021-02-06 14:23:36 -0700799 err = tpm1_oiap(dev, NULL);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200800 if (err)
801 return err;
802 }
803 if (pack_byte_string(request, sizeof(request), "sdd",
804 0, command, sizeof(command),
805 req_size_offset,
Miquel Raynalb9804e52018-05-15 11:56:59 +0200806 (u32)(sizeof(command)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200807 + TPM_REQUEST_AUTH_LENGTH),
808 req_key_handle_offset, key_handle
809 ))
810 return TPM_LIB_ERROR;
811 err = create_request_auth(request, sizeof(command), 4, &oiap_session,
Miquel Raynalc6179182018-05-15 11:57:00 +0200812 request + sizeof(command), usage_auth);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200813 if (err)
814 return err;
Simon Glassabdc7b82018-11-18 14:22:27 -0700815 err = tpm_sendrecv_command(dev, request, response, &response_length);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200816 if (err) {
817 if (err == TPM_AUTHFAIL)
818 oiap_session.valid = 0;
819 return err;
820 }
821 err = verify_response_auth(0x00000021, response,
Miquel Raynalc6179182018-05-15 11:57:00 +0200822 response_length - TPM_RESPONSE_AUTH_LENGTH,
823 0, &oiap_session,
824 response + response_length -
825 TPM_RESPONSE_AUTH_LENGTH,
826 usage_auth);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200827 if (err)
828 return err;
829
830 if (pubkey) {
831 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
Miquel Raynalc6179182018-05-15 11:57:00 +0200832 - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200833 return TPM_LIB_ERROR;
834 *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
835 - TPM_RESPONSE_AUTH_LENGTH;
836 memcpy(pubkey, response + res_pubkey_offset,
837 response_length - TPM_RESPONSE_HEADER_LENGTH
838 - TPM_RESPONSE_AUTH_LENGTH);
839 }
840
841 return 0;
842}
843
mario.six@gdsys.cc0f4b2ba2017-03-20 10:28:28 +0100844#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
Simon Glassd6a885f2021-02-06 14:23:36 -0700845u32 tpm1_find_key_sha1(struct udevice *dev, const u8 auth[20],
846 const u8 pubkey_digest[20], u32 *handle)
mario.six@gdsys.cc0f4b2ba2017-03-20 10:28:28 +0100847{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200848 u16 key_count;
849 u32 key_handles[10];
850 u8 buf[288];
851 u8 *ptr;
852 u32 err;
853 u8 digest[20];
mario.six@gdsys.cc0f4b2ba2017-03-20 10:28:28 +0100854 size_t buf_len;
855 unsigned int i;
856
857 /* fetch list of already loaded keys in the TPM */
Mathew McBridee845dd72021-11-11 04:06:27 +0000858 err = tpm1_get_capability(dev, TPM_CAP_HANDLE, TPM_RT_KEY, buf,
Simon Glassabdc7b82018-11-18 14:22:27 -0700859 sizeof(buf));
mario.six@gdsys.cc0f4b2ba2017-03-20 10:28:28 +0100860 if (err)
861 return -1;
862 key_count = get_unaligned_be16(buf);
863 ptr = buf + 2;
864 for (i = 0; i < key_count; ++i, ptr += 4)
865 key_handles[i] = get_unaligned_be32(ptr);
866
867 /* now search a(/ the) key which we can access with the given auth */
868 for (i = 0; i < key_count; ++i) {
869 buf_len = sizeof(buf);
Mathew McBridee845dd72021-11-11 04:06:27 +0000870 err = tpm1_get_pub_key_oiap(dev, key_handles[i], auth, buf, &buf_len);
mario.six@gdsys.cc0f4b2ba2017-03-20 10:28:28 +0100871 if (err && err != TPM_AUTHFAIL)
872 return -1;
873 if (err)
874 continue;
875 sha1_csum(buf, buf_len, digest);
876 if (!memcmp(digest, pubkey_digest, 20)) {
877 *handle = key_handles[i];
878 return 0;
879 }
880 }
881 return 1;
882}
883#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
884
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200885#endif /* CONFIG_TPM_AUTH_SESSIONS */
André Draszik3c605022017-10-03 16:55:52 +0100886
Simon Glassd6a885f2021-02-06 14:23:36 -0700887u32 tpm1_get_random(struct udevice *dev, void *data, u32 count)
André Draszik3c605022017-10-03 16:55:52 +0100888{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200889 const u8 command[14] = {
André Draszik3c605022017-10-03 16:55:52 +0100890 0x0, 0xc1, /* TPM_TAG */
891 0x0, 0x0, 0x0, 0xe, /* parameter size */
892 0x0, 0x0, 0x0, 0x46, /* TPM_COMMAND_CODE */
893 };
894 const size_t length_offset = 10;
895 const size_t data_size_offset = 10;
896 const size_t data_offset = 14;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200897 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
André Draszik3c605022017-10-03 16:55:52 +0100898 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200899 u32 data_size;
900 u8 *out = data;
André Draszik3c605022017-10-03 16:55:52 +0100901
902 while (count > 0) {
Miquel Raynalb9804e52018-05-15 11:56:59 +0200903 u32 this_bytes = min((size_t)count,
904 sizeof(response) - data_offset);
905 u32 err;
André Draszik3c605022017-10-03 16:55:52 +0100906
907 if (pack_byte_string(buf, sizeof(buf), "sd",
908 0, command, sizeof(command),
909 length_offset, this_bytes))
910 return TPM_LIB_ERROR;
Simon Glassabdc7b82018-11-18 14:22:27 -0700911 err = tpm_sendrecv_command(dev, buf, response,
912 &response_length);
André Draszik3c605022017-10-03 16:55:52 +0100913 if (err)
914 return err;
915 if (unpack_byte_string(response, response_length, "d",
916 data_size_offset, &data_size))
917 return TPM_LIB_ERROR;
918 if (data_size > count)
919 return TPM_LIB_ERROR;
920 if (unpack_byte_string(response, response_length, "s",
921 data_offset, out, data_size))
922 return TPM_LIB_ERROR;
923
924 count -= data_size;
925 out += data_size;
926 }
927
928 return 0;
929}