blob: 8dc144080cabc9d4d6348254023f9ad8031f7eca [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Che-liang Chiouc18f9012013-02-28 09:34:57 +00002/*
3 * Copyright (c) 2013 The Chromium OS Authors.
Reinhard Pfau4fece432013-06-26 15:55:13 +02004 * Coypright (c) 2013 Guntermann & Drunck GmbH
Che-liang Chiouc18f9012013-02-28 09:34:57 +00005 */
6
Simon Glassbccabbe2018-10-01 12:22:29 -06007#define LOG_CATEGORY UCLASS_TPM
8
Che-liang Chiouc18f9012013-02-28 09:34:57 +00009#include <common.h>
Simon Glass3e4f2fd2015-08-22 18:31:32 -060010#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Che-liang Chiouc18f9012013-02-28 09:34:57 +000012#include <asm/unaligned.h>
Simon Glass3e4f2fd2015-08-22 18:31:32 -060013#include <u-boot/sha1.h>
Miquel Raynal4c6759e2018-05-15 11:57:06 +020014#include <tpm-common.h>
15#include <tpm-v1.h>
16#include "tpm-utils.h"
Che-liang Chiouc18f9012013-02-28 09:34:57 +000017
Reinhard Pfau4fece432013-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 Raynald790f552018-05-15 11:56:59 +020026 u32 handle;
27 u8 nonce_even[DIGEST_LENGTH];
28 u8 nonce_odd[DIGEST_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +020029};
30
31static struct session_data oiap_session = {0, };
32
33#endif /* CONFIG_TPM_AUTH_SESSIONS */
34
Simon Glass3b8692a2021-02-06 14:23:36 -070035u32 tpm1_startup(struct udevice *dev, enum tpm_startup_type mode)
Che-liang Chiouc18f9012013-02-28 09:34:57 +000036{
Miquel Raynald790f552018-05-15 11:56:59 +020037 const u8 command[12] = {
Che-liang Chiouc18f9012013-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 Raynald790f552018-05-15 11:56:59 +020041 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +000042
43 if (pack_byte_string(buf, sizeof(buf), "sw",
Miquel Raynal886ccc02018-05-15 11:57:00 +020044 0, command, sizeof(command),
45 mode_offset, mode))
Che-liang Chiouc18f9012013-02-28 09:34:57 +000046 return TPM_LIB_ERROR;
47
Simon Glass8ceca1d2018-11-18 14:22:27 -070048 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +000049}
50
Simon Glass3b8692a2021-02-06 14:23:36 -070051u32 tpm1_resume(struct udevice *dev)
Simon Glassbccabbe2018-10-01 12:22:29 -060052{
Simon Glass3b8692a2021-02-06 14:23:36 -070053 return tpm1_startup(dev, TPM_ST_STATE);
Simon Glassbccabbe2018-10-01 12:22:29 -060054}
55
Simon Glass3b8692a2021-02-06 14:23:36 -070056u32 tpm1_self_test_full(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +000057{
Miquel Raynald790f552018-05-15 11:56:59 +020058 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +000059 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
60 };
Simon Glass8ceca1d2018-11-18 14:22:27 -070061 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +000062}
63
Simon Glass3b8692a2021-02-06 14:23:36 -070064u32 tpm1_continue_self_test(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +000065{
Miquel Raynald790f552018-05-15 11:56:59 +020066 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +000067 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
68 };
Simon Glass8ceca1d2018-11-18 14:22:27 -070069 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +000070}
71
Simon Glass3b8692a2021-02-06 14:23:36 -070072u32 tpm1_clear_and_reenable(struct udevice *dev)
Simon Glassbccabbe2018-10-01 12:22:29 -060073{
74 u32 ret;
75
76 log_info("TPM: Clear and re-enable\n");
Simon Glass3b8692a2021-02-06 14:23:36 -070077 ret = tpm1_force_clear(dev);
Simon Glassbccabbe2018-10-01 12:22:29 -060078 if (ret != TPM_SUCCESS) {
79 log_err("Can't initiate a force clear\n");
80 return ret;
81 }
82
Simon Glass3b8692a2021-02-06 14:23:36 -070083 ret = tpm1_physical_enable(dev);
84 if (ret != TPM_SUCCESS) {
85 log_err("TPM: Can't set enabled state\n");
86 return ret;
87 }
Simon Glassbccabbe2018-10-01 12:22:29 -060088
Simon Glass3b8692a2021-02-06 14:23:36 -070089 ret = tpm1_physical_set_deactivated(dev, 0);
90 if (ret != TPM_SUCCESS) {
91 log_err("TPM: Can't set deactivated state\n");
92 return ret;
Simon Glassbccabbe2018-10-01 12:22:29 -060093 }
Simon Glassbccabbe2018-10-01 12:22:29 -060094
95 return TPM_SUCCESS;
96}
97
Simon Glass3b8692a2021-02-06 14:23:36 -070098u32 tpm1_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size)
Che-liang Chiouc18f9012013-02-28 09:34:57 +000099{
Miquel Raynald790f552018-05-15 11:56:59 +0200100 const u8 command[101] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000101 0x0, 0xc1, /* TPM_TAG */
102 0x0, 0x0, 0x0, 0x65, /* parameter size */
103 0x0, 0x0, 0x0, 0xcc, /* TPM_COMMAND_CODE */
104 /* TPM_NV_DATA_PUBLIC->... */
105 0x0, 0x18, /* ...->TPM_STRUCTURE_TAG */
106 0, 0, 0, 0, /* ...->TPM_NV_INDEX */
107 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
108 0x0, 0x3,
109 0, 0, 0,
110 0x1f,
111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
113 0x0, 0x3,
114 0, 0, 0,
115 0x1f,
116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
117 /* TPM_NV_ATTRIBUTES->... */
118 0x0, 0x17, /* ...->TPM_STRUCTURE_TAG */
119 0, 0, 0, 0, /* ...->attributes */
120 /* End of TPM_NV_ATTRIBUTES */
121 0, /* bReadSTClear */
122 0, /* bWriteSTClear */
123 0, /* bWriteDefine */
124 0, 0, 0, 0, /* size */
125 };
126 const size_t index_offset = 12;
127 const size_t perm_offset = 70;
128 const size_t size_offset = 77;
Miquel Raynald790f552018-05-15 11:56:59 +0200129 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000130
131 if (pack_byte_string(buf, sizeof(buf), "sddd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200132 0, command, sizeof(command),
133 index_offset, index,
134 perm_offset, perm,
135 size_offset, size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000136 return TPM_LIB_ERROR;
137
Simon Glass8ceca1d2018-11-18 14:22:27 -0700138 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000139}
140
Simon Glass3b8692a2021-02-06 14:23:36 -0700141u32 tpm1_nv_set_locked(struct udevice *dev)
Simon Glassbccabbe2018-10-01 12:22:29 -0600142{
Simon Glass3b8692a2021-02-06 14:23:36 -0700143 return tpm1_nv_define_space(dev, TPM_NV_INDEX_LOCK, 0, 0);
Simon Glassbccabbe2018-10-01 12:22:29 -0600144}
145
Simon Glass3b8692a2021-02-06 14:23:36 -0700146u32 tpm1_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000147{
Miquel Raynald790f552018-05-15 11:56:59 +0200148 const u8 command[22] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000149 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
150 };
151 const size_t index_offset = 10;
152 const size_t length_offset = 18;
153 const size_t data_size_offset = 10;
154 const size_t data_offset = 14;
Miquel Raynald790f552018-05-15 11:56:59 +0200155 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000156 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200157 u32 data_size;
158 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000159
160 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200161 0, command, sizeof(command),
162 index_offset, index,
163 length_offset, count))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000164 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700165 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000166 if (err)
167 return err;
168 if (unpack_byte_string(response, response_length, "d",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200169 data_size_offset, &data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000170 return TPM_LIB_ERROR;
171 if (data_size > count)
172 return TPM_LIB_ERROR;
173 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200174 data_offset, data, data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000175 return TPM_LIB_ERROR;
176
177 return 0;
178}
179
Simon Glass3b8692a2021-02-06 14:23:36 -0700180u32 tpm1_nv_write_value(struct udevice *dev, u32 index, const void *data,
181 u32 length)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000182{
Miquel Raynald790f552018-05-15 11:56:59 +0200183 const u8 command[256] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000184 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
185 };
186 const size_t command_size_offset = 2;
187 const size_t index_offset = 10;
188 const size_t length_offset = 18;
189 const size_t data_offset = 22;
190 const size_t write_info_size = 12;
Miquel Raynald790f552018-05-15 11:56:59 +0200191 const u32 total_length =
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000192 TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
Miquel Raynald790f552018-05-15 11:56:59 +0200193 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000194 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200195 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000196
197 if (pack_byte_string(buf, sizeof(buf), "sddds",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200198 0, command, sizeof(command),
199 command_size_offset, total_length,
200 index_offset, index,
201 length_offset, length,
202 data_offset, data, length))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000203 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700204 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000205 if (err)
206 return err;
207
208 return 0;
209}
210
Simon Glass3b8692a2021-02-06 14:23:36 -0700211u32 tpm1_extend(struct udevice *dev, u32 index, const void *in_digest,
212 void *out_digest)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000213{
Miquel Raynald790f552018-05-15 11:56:59 +0200214 const u8 command[34] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000215 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
216 };
217 const size_t index_offset = 10;
218 const size_t in_digest_offset = 14;
219 const size_t out_digest_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200220 u8 buf[COMMAND_BUFFER_SIZE];
221 u8 response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000222 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200223 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000224
225 if (pack_byte_string(buf, sizeof(buf), "sds",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200226 0, command, sizeof(command),
227 index_offset, index,
228 in_digest_offset, in_digest,
229 PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000230 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700231 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000232 if (err)
233 return err;
234
235 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200236 out_digest_offset, out_digest,
237 PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000238 return TPM_LIB_ERROR;
239
240 return 0;
241}
242
Simon Glass3b8692a2021-02-06 14:23:36 -0700243u32 tpm1_pcr_read(struct udevice *dev, u32 index, void *data, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000244{
Miquel Raynald790f552018-05-15 11:56:59 +0200245 const u8 command[14] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000246 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
247 };
248 const size_t index_offset = 10;
249 const size_t out_digest_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200250 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000251 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200252 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000253
254 if (count < PCR_DIGEST_LENGTH)
255 return TPM_LIB_ERROR;
256
257 if (pack_byte_string(buf, sizeof(buf), "sd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200258 0, command, sizeof(command),
259 index_offset, index))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000260 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700261 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000262 if (err)
263 return err;
264 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200265 out_digest_offset, data, PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000266 return TPM_LIB_ERROR;
267
268 return 0;
269}
270
Simon Glass3b8692a2021-02-06 14:23:36 -0700271u32 tpm1_tsc_physical_presence(struct udevice *dev, u16 presence)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000272{
Miquel Raynald790f552018-05-15 11:56:59 +0200273 const u8 command[12] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000274 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
275 };
276 const size_t presence_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200277 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000278
279 if (pack_byte_string(buf, sizeof(buf), "sw",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200280 0, command, sizeof(command),
281 presence_offset, presence))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000282 return TPM_LIB_ERROR;
283
Simon Glass8ceca1d2018-11-18 14:22:27 -0700284 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000285}
286
Simon Glass3b8692a2021-02-06 14:23:36 -0700287u32 tpm1_finalise_physical_presence(struct udevice *dev)
Simon Glassbccabbe2018-10-01 12:22:29 -0600288{
289 const u8 command[12] = {
290 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x2, 0xa0,
291 };
292
Simon Glass8ceca1d2018-11-18 14:22:27 -0700293 return tpm_sendrecv_command(dev, command, NULL, NULL);
Simon Glassbccabbe2018-10-01 12:22:29 -0600294}
295
Simon Glass3b8692a2021-02-06 14:23:36 -0700296u32 tpm1_read_pubek(struct udevice *dev, void *data, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000297{
Miquel Raynald790f552018-05-15 11:56:59 +0200298 const u8 command[30] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000299 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
300 };
301 const size_t response_size_offset = 2;
302 const size_t data_offset = 10;
303 const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
Miquel Raynald790f552018-05-15 11:56:59 +0200304 u8 response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000305 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200306 u32 data_size;
307 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000308
Simon Glass8ceca1d2018-11-18 14:22:27 -0700309 err = tpm_sendrecv_command(dev, command, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000310 if (err)
311 return err;
312 if (unpack_byte_string(response, response_length, "d",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200313 response_size_offset, &data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000314 return TPM_LIB_ERROR;
315 if (data_size < header_and_checksum_size)
316 return TPM_LIB_ERROR;
317 data_size -= header_and_checksum_size;
318 if (data_size > count)
319 return TPM_LIB_ERROR;
320 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200321 data_offset, data, data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000322 return TPM_LIB_ERROR;
323
324 return 0;
325}
326
Simon Glass3b8692a2021-02-06 14:23:36 -0700327u32 tpm1_force_clear(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000328{
Miquel Raynald790f552018-05-15 11:56:59 +0200329 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000330 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
331 };
332
Simon Glass8ceca1d2018-11-18 14:22:27 -0700333 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000334}
335
Simon Glass3b8692a2021-02-06 14:23:36 -0700336u32 tpm1_physical_enable(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000337{
Miquel Raynald790f552018-05-15 11:56:59 +0200338 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000339 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
340 };
341
Simon Glass8ceca1d2018-11-18 14:22:27 -0700342 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000343}
344
Simon Glass3b8692a2021-02-06 14:23:36 -0700345u32 tpm1_physical_disable(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000346{
Miquel Raynald790f552018-05-15 11:56:59 +0200347 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000348 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
349 };
350
Simon Glass8ceca1d2018-11-18 14:22:27 -0700351 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000352}
353
Simon Glass3b8692a2021-02-06 14:23:36 -0700354u32 tpm1_physical_set_deactivated(struct udevice *dev, u8 state)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000355{
Miquel Raynald790f552018-05-15 11:56:59 +0200356 const u8 command[11] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000357 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
358 };
359 const size_t state_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200360 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000361
362 if (pack_byte_string(buf, sizeof(buf), "sb",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200363 0, command, sizeof(command),
364 state_offset, state))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000365 return TPM_LIB_ERROR;
366
Simon Glass8ceca1d2018-11-18 14:22:27 -0700367 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000368}
369
Simon Glass3b8692a2021-02-06 14:23:36 -0700370u32 tpm1_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap,
371 void *cap, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000372{
Miquel Raynald790f552018-05-15 11:56:59 +0200373 const u8 command[22] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000374 0x0, 0xc1, /* TPM_TAG */
375 0x0, 0x0, 0x0, 0x16, /* parameter size */
376 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
377 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */
378 0x0, 0x0, 0x0, 0x4, /* subcap size */
379 0x0, 0x0, 0x0, 0x0, /* subcap value */
380 };
381 const size_t cap_area_offset = 10;
382 const size_t sub_cap_offset = 18;
383 const size_t cap_offset = 14;
384 const size_t cap_size_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200385 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000386 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200387 u32 cap_size;
388 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000389
390 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200391 0, command, sizeof(command),
392 cap_area_offset, cap_area,
393 sub_cap_offset, sub_cap))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000394 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700395 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000396 if (err)
397 return err;
398 if (unpack_byte_string(response, response_length, "d",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200399 cap_size_offset, &cap_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000400 return TPM_LIB_ERROR;
401 if (cap_size > response_length || cap_size > count)
402 return TPM_LIB_ERROR;
403 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200404 cap_offset, cap, cap_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000405 return TPM_LIB_ERROR;
406
407 return 0;
408}
Reinhard Pfau4fece432013-06-26 15:55:13 +0200409
Simon Glass3b8692a2021-02-06 14:23:36 -0700410u32 tpm1_get_permanent_flags(struct udevice *dev,
411 struct tpm_permanent_flags *pflags)
Simon Glassff9f04a2015-08-22 18:31:41 -0600412{
Miquel Raynald790f552018-05-15 11:56:59 +0200413 const u8 command[22] = {
Simon Glassff9f04a2015-08-22 18:31:41 -0600414 0x0, 0xc1, /* TPM_TAG */
415 0x0, 0x0, 0x0, 0x16, /* parameter size */
416 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
417 0x0, 0x0, 0x0, 0x4, /* TPM_CAP_FLAG_PERM */
418 0x0, 0x0, 0x0, 0x4, /* subcap size */
419 0x0, 0x0, 0x1, 0x8, /* subcap value */
420 };
André Draszik1361fbc2017-10-03 16:55:51 +0100421 const size_t data_size_offset = TPM_HEADER_SIZE;
Miquel Raynald790f552018-05-15 11:56:59 +0200422 const size_t data_offset = TPM_HEADER_SIZE + sizeof(u32);
423 u8 response[COMMAND_BUFFER_SIZE];
Simon Glassff9f04a2015-08-22 18:31:41 -0600424 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200425 u32 err;
426 u32 data_size;
Simon Glassff9f04a2015-08-22 18:31:41 -0600427
Simon Glass8ceca1d2018-11-18 14:22:27 -0700428 err = tpm_sendrecv_command(dev, command, response, &response_length);
Simon Glassff9f04a2015-08-22 18:31:41 -0600429 if (err)
430 return err;
André Draszik1361fbc2017-10-03 16:55:51 +0100431 if (unpack_byte_string(response, response_length, "d",
Simon Glassbccabbe2018-10-01 12:22:29 -0600432 data_size_offset, &data_size)) {
433 log_err("Cannot unpack data size\n");
André Draszik1361fbc2017-10-03 16:55:51 +0100434 return TPM_LIB_ERROR;
Simon Glassbccabbe2018-10-01 12:22:29 -0600435 }
436 if (data_size < sizeof(*pflags)) {
437 log_err("Data size too small\n");
André Draszik1361fbc2017-10-03 16:55:51 +0100438 return TPM_LIB_ERROR;
Simon Glassbccabbe2018-10-01 12:22:29 -0600439 }
André Draszik1361fbc2017-10-03 16:55:51 +0100440 if (unpack_byte_string(response, response_length, "s",
Simon Glassbccabbe2018-10-01 12:22:29 -0600441 data_offset, pflags, sizeof(*pflags))) {
442 log_err("Cannot unpack pflags\n");
André Draszik1361fbc2017-10-03 16:55:51 +0100443 return TPM_LIB_ERROR;
Simon Glassbccabbe2018-10-01 12:22:29 -0600444 }
Simon Glassff9f04a2015-08-22 18:31:41 -0600445
446 return 0;
447}
448
Simon Glass3b8692a2021-02-06 14:23:36 -0700449u32 tpm1_get_permissions(struct udevice *dev, u32 index, u32 *perm)
Simon Glassff9f04a2015-08-22 18:31:41 -0600450{
Miquel Raynald790f552018-05-15 11:56:59 +0200451 const u8 command[22] = {
Simon Glassff9f04a2015-08-22 18:31:41 -0600452 0x0, 0xc1, /* TPM_TAG */
453 0x0, 0x0, 0x0, 0x16, /* parameter size */
454 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
455 0x0, 0x0, 0x0, 0x11,
456 0x0, 0x0, 0x0, 0x4,
457 };
458 const size_t index_offset = 18;
459 const size_t perm_offset = 60;
Miquel Raynald790f552018-05-15 11:56:59 +0200460 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Simon Glassff9f04a2015-08-22 18:31:41 -0600461 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200462 u32 err;
Simon Glassff9f04a2015-08-22 18:31:41 -0600463
464 if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command),
465 index_offset, index))
466 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700467 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Simon Glassff9f04a2015-08-22 18:31:41 -0600468 if (err)
469 return err;
470 if (unpack_byte_string(response, response_length, "d",
471 perm_offset, perm))
472 return TPM_LIB_ERROR;
473
474 return 0;
475}
476
Mario Six4eceb6c2017-01-11 16:00:50 +0100477#ifdef CONFIG_TPM_FLUSH_RESOURCES
Simon Glass3b8692a2021-02-06 14:23:36 -0700478u32 tpm1_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type)
Mario Six4eceb6c2017-01-11 16:00:50 +0100479{
Miquel Raynald790f552018-05-15 11:56:59 +0200480 const u8 command[18] = {
Mario Six4eceb6c2017-01-11 16:00:50 +0100481 0x00, 0xc1, /* TPM_TAG */
482 0x00, 0x00, 0x00, 0x12, /* parameter size */
483 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
484 0x00, 0x00, 0x00, 0x00, /* key handle */
485 0x00, 0x00, 0x00, 0x00, /* resource type */
486 };
487 const size_t key_handle_offset = 10;
488 const size_t resource_type_offset = 14;
Miquel Raynald790f552018-05-15 11:56:59 +0200489 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Mario Six4eceb6c2017-01-11 16:00:50 +0100490 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200491 u32 err;
Mario Six4eceb6c2017-01-11 16:00:50 +0100492
493 if (pack_byte_string(buf, sizeof(buf), "sdd",
494 0, command, sizeof(command),
495 key_handle_offset, key_handle,
496 resource_type_offset, resource_type))
497 return TPM_LIB_ERROR;
498
Simon Glass8ceca1d2018-11-18 14:22:27 -0700499 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Mario Six4eceb6c2017-01-11 16:00:50 +0100500 if (err)
501 return err;
502 return 0;
503}
504#endif /* CONFIG_TPM_FLUSH_RESOURCES */
505
Reinhard Pfau4fece432013-06-26 15:55:13 +0200506#ifdef CONFIG_TPM_AUTH_SESSIONS
507
508/**
509 * Fill an authentication block in a request.
510 * This func can create the first as well as the second auth block (for
511 * double authorized commands).
512 *
513 * @param request pointer to the request (w/ uninitialised auth data)
514 * @param request_len0 length of the request without auth data
515 * @param handles_len length of the handles area in request
516 * @param auth_session pointer to the (valid) auth session to be used
517 * @param request_auth pointer to the auth block of the request to be filled
518 * @param auth authentication data (HMAC key)
519 */
Miquel Raynald790f552018-05-15 11:56:59 +0200520static u32 create_request_auth(const void *request, size_t request_len0,
521 size_t handles_len,
522 struct session_data *auth_session,
523 void *request_auth, const void *auth)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200524{
Miquel Raynald790f552018-05-15 11:56:59 +0200525 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200526 sha1_context hash_ctx;
527 const size_t command_code_offset = 6;
528 const size_t auth_nonce_odd_offset = 4;
529 const size_t auth_continue_offset = 24;
530 const size_t auth_auth_offset = 25;
531
532 if (!auth_session || !auth_session->valid)
533 return TPM_LIB_ERROR;
534
535 sha1_starts(&hash_ctx);
536 sha1_update(&hash_ctx, request + command_code_offset, 4);
537 if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
538 sha1_update(&hash_ctx,
539 request + TPM_REQUEST_HEADER_LENGTH + handles_len,
540 request_len0 - TPM_REQUEST_HEADER_LENGTH
541 - handles_len);
542 sha1_finish(&hash_ctx, hmac_data);
543
544 sha1_starts(&hash_ctx);
545 sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
546 sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
547 sha1_finish(&hash_ctx, auth_session->nonce_odd);
548
549 if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
550 0, auth_session->handle,
551 auth_nonce_odd_offset, auth_session->nonce_odd,
552 DIGEST_LENGTH,
553 auth_continue_offset, 1))
554 return TPM_LIB_ERROR;
555 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
556 DIGEST_LENGTH,
557 auth_session->nonce_even,
558 DIGEST_LENGTH,
559 2 * DIGEST_LENGTH,
560 request_auth + auth_nonce_odd_offset,
561 DIGEST_LENGTH + 1))
562 return TPM_LIB_ERROR;
563 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
564 request_auth + auth_auth_offset);
565
566 return TPM_SUCCESS;
567}
568
569/**
570 * Verify an authentication block in a response.
571 * Since this func updates the nonce_even in the session data it has to be
572 * called when receiving a succesfull AUTH response.
573 * This func can verify the first as well as the second auth block (for
574 * double authorized commands).
575 *
576 * @param command_code command code of the request
577 * @param response pointer to the request (w/ uninitialised auth data)
578 * @param handles_len length of the handles area in response
579 * @param auth_session pointer to the (valid) auth session to be used
580 * @param response_auth pointer to the auth block of the response to be verified
581 * @param auth authentication data (HMAC key)
582 */
Miquel Raynald790f552018-05-15 11:56:59 +0200583static u32 verify_response_auth(u32 command_code, const void *response,
584 size_t response_len0, size_t handles_len,
585 struct session_data *auth_session,
586 const void *response_auth, const void *auth)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200587{
Miquel Raynald790f552018-05-15 11:56:59 +0200588 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
589 u8 computed_auth[DIGEST_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200590 sha1_context hash_ctx;
591 const size_t return_code_offset = 6;
592 const size_t auth_continue_offset = 20;
593 const size_t auth_auth_offset = 21;
Miquel Raynald790f552018-05-15 11:56:59 +0200594 u8 auth_continue;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200595
596 if (!auth_session || !auth_session->valid)
597 return TPM_AUTHFAIL;
598 if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
599 0, command_code))
600 return TPM_LIB_ERROR;
601 if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
602 return TPM_LIB_ERROR;
603
604 sha1_starts(&hash_ctx);
605 sha1_update(&hash_ctx, response + return_code_offset, 4);
606 sha1_update(&hash_ctx, hmac_data, 4);
607 if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
608 sha1_update(&hash_ctx,
609 response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
610 response_len0 - TPM_RESPONSE_HEADER_LENGTH
611 - handles_len);
612 sha1_finish(&hash_ctx, hmac_data);
613
614 memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
Miquel Raynald790f552018-05-15 11:56:59 +0200615 auth_continue = ((u8 *)response_auth)[auth_continue_offset];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200616 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
617 DIGEST_LENGTH,
618 response_auth,
619 DIGEST_LENGTH,
620 2 * DIGEST_LENGTH,
621 auth_session->nonce_odd,
622 DIGEST_LENGTH,
623 3 * DIGEST_LENGTH,
624 auth_continue))
625 return TPM_LIB_ERROR;
626
627 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
628 computed_auth);
629
630 if (memcmp(computed_auth, response_auth + auth_auth_offset,
631 DIGEST_LENGTH))
632 return TPM_AUTHFAIL;
633
634 return TPM_SUCCESS;
635}
636
Simon Glass3b8692a2021-02-06 14:23:36 -0700637u32 tpm1_terminate_auth_session(struct udevice *dev, u32 auth_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200638{
Miquel Raynald790f552018-05-15 11:56:59 +0200639 const u8 command[18] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200640 0x00, 0xc1, /* TPM_TAG */
641 0x00, 0x00, 0x00, 0x00, /* parameter size */
642 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
643 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
Miquel Raynala59aa342018-05-15 11:57:02 +0200644 0x00, 0x00, 0x00, 0x02, /* TPM_RESOURCE_TYPE */
Reinhard Pfau4fece432013-06-26 15:55:13 +0200645 };
646 const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200647 u8 request[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200648
649 if (pack_byte_string(request, sizeof(request), "sd",
650 0, command, sizeof(command),
651 req_handle_offset, auth_handle))
652 return TPM_LIB_ERROR;
653 if (oiap_session.valid && oiap_session.handle == auth_handle)
654 oiap_session.valid = 0;
655
Simon Glass8ceca1d2018-11-18 14:22:27 -0700656 return tpm_sendrecv_command(dev, request, NULL, NULL);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200657}
658
Simon Glass3b8692a2021-02-06 14:23:36 -0700659u32 tpm1_end_oiap(struct udevice *dev)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200660{
Miquel Raynald790f552018-05-15 11:56:59 +0200661 u32 err = TPM_SUCCESS;
Miquel Raynal82b05662018-05-15 11:57:03 +0200662
Reinhard Pfau4fece432013-06-26 15:55:13 +0200663 if (oiap_session.valid)
Simon Glass3b8692a2021-02-06 14:23:36 -0700664 err = tpm1_terminate_auth_session(dev, oiap_session.handle);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200665 return err;
666}
667
Simon Glass3b8692a2021-02-06 14:23:36 -0700668u32 tpm1_oiap(struct udevice *dev, u32 *auth_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200669{
Miquel Raynald790f552018-05-15 11:56:59 +0200670 const u8 command[10] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200671 0x00, 0xc1, /* TPM_TAG */
672 0x00, 0x00, 0x00, 0x0a, /* parameter size */
673 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
674 };
675 const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
676 const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
Miquel Raynald790f552018-05-15 11:56:59 +0200677 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200678 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200679 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200680
681 if (oiap_session.valid)
Simon Glass3b8692a2021-02-06 14:23:36 -0700682 tpm1_terminate_auth_session(dev, oiap_session.handle);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200683
Simon Glass8ceca1d2018-11-18 14:22:27 -0700684 err = tpm_sendrecv_command(dev, command, response, &response_length);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200685 if (err)
686 return err;
687 if (unpack_byte_string(response, response_length, "ds",
688 res_auth_handle_offset, &oiap_session.handle,
689 res_nonce_even_offset, &oiap_session.nonce_even,
Miquel Raynald790f552018-05-15 11:56:59 +0200690 (u32)DIGEST_LENGTH))
Reinhard Pfau4fece432013-06-26 15:55:13 +0200691 return TPM_LIB_ERROR;
692 oiap_session.valid = 1;
693 if (auth_handle)
694 *auth_handle = oiap_session.handle;
695 return 0;
696}
697
Simon Glass3b8692a2021-02-06 14:23:36 -0700698u32 tpm1_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key,
699 size_t key_length, const void *parent_key_usage_auth,
700 u32 *key_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200701{
Miquel Raynald790f552018-05-15 11:56:59 +0200702 const u8 command[14] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200703 0x00, 0xc2, /* TPM_TAG */
704 0x00, 0x00, 0x00, 0x00, /* parameter size */
705 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
706 0x00, 0x00, 0x00, 0x00, /* parent handle */
707 };
708 const size_t req_size_offset = 2;
709 const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
710 const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
711 const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200712 u8 request[sizeof(command) + TPM_KEY12_MAX_LENGTH +
713 TPM_REQUEST_AUTH_LENGTH];
714 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200715 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200716 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200717
718 if (!oiap_session.valid) {
Simon Glass3b8692a2021-02-06 14:23:36 -0700719 err = tpm1_oiap(dev, NULL);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200720 if (err)
721 return err;
722 }
723 if (pack_byte_string(request, sizeof(request), "sdds",
724 0, command, sizeof(command),
725 req_size_offset,
726 sizeof(command) + key_length
727 + TPM_REQUEST_AUTH_LENGTH,
728 req_parent_handle_offset, parent_handle,
729 req_key_offset, key, key_length
730 ))
731 return TPM_LIB_ERROR;
732
733 err = create_request_auth(request, sizeof(command) + key_length, 4,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200734 &oiap_session,
735 request + sizeof(command) + key_length,
736 parent_key_usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200737 if (err)
738 return err;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700739 err = tpm_sendrecv_command(dev, request, response, &response_length);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200740 if (err) {
741 if (err == TPM_AUTHFAIL)
742 oiap_session.valid = 0;
743 return err;
744 }
745
746 err = verify_response_auth(0x00000041, response,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200747 response_length - TPM_RESPONSE_AUTH_LENGTH,
748 4, &oiap_session,
749 response + response_length -
750 TPM_RESPONSE_AUTH_LENGTH,
751 parent_key_usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200752 if (err)
753 return err;
754
755 if (key_handle) {
756 if (unpack_byte_string(response, response_length, "d",
757 res_handle_offset, key_handle))
758 return TPM_LIB_ERROR;
759 }
760
761 return 0;
762}
763
Simon Glass3b8692a2021-02-06 14:23:36 -0700764u32 tpm1_get_pub_key_oiap(struct udevice *dev, u32 key_handle,
765 const void *usage_auth, void *pubkey,
766 size_t *pubkey_len)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200767{
Miquel Raynald790f552018-05-15 11:56:59 +0200768 const u8 command[14] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200769 0x00, 0xc2, /* TPM_TAG */
770 0x00, 0x00, 0x00, 0x00, /* parameter size */
771 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
772 0x00, 0x00, 0x00, 0x00, /* key handle */
773 };
774 const size_t req_size_offset = 2;
775 const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
776 const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200777 u8 request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
778 u8 response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH +
779 TPM_RESPONSE_AUTH_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200780 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200781 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200782
783 if (!oiap_session.valid) {
Simon Glass3b8692a2021-02-06 14:23:36 -0700784 err = tpm1_oiap(dev, NULL);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200785 if (err)
786 return err;
787 }
788 if (pack_byte_string(request, sizeof(request), "sdd",
789 0, command, sizeof(command),
790 req_size_offset,
Miquel Raynald790f552018-05-15 11:56:59 +0200791 (u32)(sizeof(command)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200792 + TPM_REQUEST_AUTH_LENGTH),
793 req_key_handle_offset, key_handle
794 ))
795 return TPM_LIB_ERROR;
796 err = create_request_auth(request, sizeof(command), 4, &oiap_session,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200797 request + sizeof(command), usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200798 if (err)
799 return err;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700800 err = tpm_sendrecv_command(dev, request, response, &response_length);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200801 if (err) {
802 if (err == TPM_AUTHFAIL)
803 oiap_session.valid = 0;
804 return err;
805 }
806 err = verify_response_auth(0x00000021, response,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200807 response_length - TPM_RESPONSE_AUTH_LENGTH,
808 0, &oiap_session,
809 response + response_length -
810 TPM_RESPONSE_AUTH_LENGTH,
811 usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200812 if (err)
813 return err;
814
815 if (pubkey) {
816 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
Miquel Raynal886ccc02018-05-15 11:57:00 +0200817 - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200818 return TPM_LIB_ERROR;
819 *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
820 - TPM_RESPONSE_AUTH_LENGTH;
821 memcpy(pubkey, response + res_pubkey_offset,
822 response_length - TPM_RESPONSE_HEADER_LENGTH
823 - TPM_RESPONSE_AUTH_LENGTH);
824 }
825
826 return 0;
827}
828
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100829#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
Simon Glass3b8692a2021-02-06 14:23:36 -0700830u32 tpm1_find_key_sha1(struct udevice *dev, const u8 auth[20],
831 const u8 pubkey_digest[20], u32 *handle)
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100832{
Miquel Raynald790f552018-05-15 11:56:59 +0200833 u16 key_count;
834 u32 key_handles[10];
835 u8 buf[288];
836 u8 *ptr;
837 u32 err;
838 u8 digest[20];
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100839 size_t buf_len;
840 unsigned int i;
841
842 /* fetch list of already loaded keys in the TPM */
Simon Glass8ceca1d2018-11-18 14:22:27 -0700843 err = tpm_get_capability(dev, TPM_CAP_HANDLE, TPM_RT_KEY, buf,
844 sizeof(buf));
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100845 if (err)
846 return -1;
847 key_count = get_unaligned_be16(buf);
848 ptr = buf + 2;
849 for (i = 0; i < key_count; ++i, ptr += 4)
850 key_handles[i] = get_unaligned_be32(ptr);
851
852 /* now search a(/ the) key which we can access with the given auth */
853 for (i = 0; i < key_count; ++i) {
854 buf_len = sizeof(buf);
855 err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len);
856 if (err && err != TPM_AUTHFAIL)
857 return -1;
858 if (err)
859 continue;
860 sha1_csum(buf, buf_len, digest);
861 if (!memcmp(digest, pubkey_digest, 20)) {
862 *handle = key_handles[i];
863 return 0;
864 }
865 }
866 return 1;
867}
868#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
869
Reinhard Pfau4fece432013-06-26 15:55:13 +0200870#endif /* CONFIG_TPM_AUTH_SESSIONS */
André Draszik2c6e5ff2017-10-03 16:55:52 +0100871
Simon Glass3b8692a2021-02-06 14:23:36 -0700872u32 tpm1_get_random(struct udevice *dev, void *data, u32 count)
André Draszik2c6e5ff2017-10-03 16:55:52 +0100873{
Miquel Raynald790f552018-05-15 11:56:59 +0200874 const u8 command[14] = {
André Draszik2c6e5ff2017-10-03 16:55:52 +0100875 0x0, 0xc1, /* TPM_TAG */
876 0x0, 0x0, 0x0, 0xe, /* parameter size */
877 0x0, 0x0, 0x0, 0x46, /* TPM_COMMAND_CODE */
878 };
879 const size_t length_offset = 10;
880 const size_t data_size_offset = 10;
881 const size_t data_offset = 14;
Miquel Raynald790f552018-05-15 11:56:59 +0200882 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
André Draszik2c6e5ff2017-10-03 16:55:52 +0100883 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200884 u32 data_size;
885 u8 *out = data;
André Draszik2c6e5ff2017-10-03 16:55:52 +0100886
887 while (count > 0) {
Miquel Raynald790f552018-05-15 11:56:59 +0200888 u32 this_bytes = min((size_t)count,
889 sizeof(response) - data_offset);
890 u32 err;
André Draszik2c6e5ff2017-10-03 16:55:52 +0100891
892 if (pack_byte_string(buf, sizeof(buf), "sd",
893 0, command, sizeof(command),
894 length_offset, this_bytes))
895 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700896 err = tpm_sendrecv_command(dev, buf, response,
897 &response_length);
André Draszik2c6e5ff2017-10-03 16:55:52 +0100898 if (err)
899 return err;
900 if (unpack_byte_string(response, response_length, "d",
901 data_size_offset, &data_size))
902 return TPM_LIB_ERROR;
903 if (data_size > count)
904 return TPM_LIB_ERROR;
905 if (unpack_byte_string(response, response_length, "s",
906 data_offset, out, data_size))
907 return TPM_LIB_ERROR;
908
909 count -= data_size;
910 out += data_size;
911 }
912
913 return 0;
914}