blob: a846fe00dd3ef4cf4a6f74c3b041156982c9e89c [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 Glass8ceca1d2018-11-18 14:22:27 -070035u32 tpm_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 Glass8ceca1d2018-11-18 14:22:27 -070051u32 tpm_resume(struct udevice *dev)
Simon Glassbccabbe2018-10-01 12:22:29 -060052{
Simon Glass8ceca1d2018-11-18 14:22:27 -070053 return tpm_startup(dev, TPM_ST_STATE);
Simon Glassbccabbe2018-10-01 12:22:29 -060054}
55
Simon Glass8ceca1d2018-11-18 14:22:27 -070056u32 tpm_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 Glass8ceca1d2018-11-18 14:22:27 -070064u32 tpm_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 Glass8ceca1d2018-11-18 14:22:27 -070072u32 tpm_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 Glass8ceca1d2018-11-18 14:22:27 -070077 ret = tpm_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 Glasse03dbde2018-11-23 21:29:32 -070083 if (tpm_get_version(dev) == TPM_V1) {
84 ret = tpm_physical_enable(dev);
85 if (ret != TPM_SUCCESS) {
86 log_err("TPM: Can't set enabled state\n");
87 return ret;
88 }
Simon Glassbccabbe2018-10-01 12:22:29 -060089
Simon Glasse03dbde2018-11-23 21:29:32 -070090 ret = tpm_physical_set_deactivated(dev, 0);
91 if (ret != TPM_SUCCESS) {
92 log_err("TPM: Can't set deactivated state\n");
93 return ret;
94 }
Simon Glassbccabbe2018-10-01 12:22:29 -060095 }
Simon Glassbccabbe2018-10-01 12:22:29 -060096
97 return TPM_SUCCESS;
98}
99
Simon Glass8ceca1d2018-11-18 14:22:27 -0700100u32 tpm_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000101{
Miquel Raynald790f552018-05-15 11:56:59 +0200102 const u8 command[101] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000103 0x0, 0xc1, /* TPM_TAG */
104 0x0, 0x0, 0x0, 0x65, /* parameter size */
105 0x0, 0x0, 0x0, 0xcc, /* TPM_COMMAND_CODE */
106 /* TPM_NV_DATA_PUBLIC->... */
107 0x0, 0x18, /* ...->TPM_STRUCTURE_TAG */
108 0, 0, 0, 0, /* ...->TPM_NV_INDEX */
109 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
110 0x0, 0x3,
111 0, 0, 0,
112 0x1f,
113 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
114 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
115 0x0, 0x3,
116 0, 0, 0,
117 0x1f,
118 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
119 /* TPM_NV_ATTRIBUTES->... */
120 0x0, 0x17, /* ...->TPM_STRUCTURE_TAG */
121 0, 0, 0, 0, /* ...->attributes */
122 /* End of TPM_NV_ATTRIBUTES */
123 0, /* bReadSTClear */
124 0, /* bWriteSTClear */
125 0, /* bWriteDefine */
126 0, 0, 0, 0, /* size */
127 };
128 const size_t index_offset = 12;
129 const size_t perm_offset = 70;
130 const size_t size_offset = 77;
Miquel Raynald790f552018-05-15 11:56:59 +0200131 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000132
133 if (pack_byte_string(buf, sizeof(buf), "sddd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200134 0, command, sizeof(command),
135 index_offset, index,
136 perm_offset, perm,
137 size_offset, size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000138 return TPM_LIB_ERROR;
139
Simon Glass8ceca1d2018-11-18 14:22:27 -0700140 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000141}
142
Simon Glass8ceca1d2018-11-18 14:22:27 -0700143u32 tpm_nv_set_locked(struct udevice *dev)
Simon Glassbccabbe2018-10-01 12:22:29 -0600144{
Simon Glass8ceca1d2018-11-18 14:22:27 -0700145 return tpm_nv_define_space(dev, TPM_NV_INDEX_LOCK, 0, 0);
Simon Glassbccabbe2018-10-01 12:22:29 -0600146}
147
Simon Glass8ceca1d2018-11-18 14:22:27 -0700148u32 tpm_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000149{
Miquel Raynald790f552018-05-15 11:56:59 +0200150 const u8 command[22] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000151 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
152 };
153 const size_t index_offset = 10;
154 const size_t length_offset = 18;
155 const size_t data_size_offset = 10;
156 const size_t data_offset = 14;
Miquel Raynald790f552018-05-15 11:56:59 +0200157 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000158 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200159 u32 data_size;
160 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000161
162 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200163 0, command, sizeof(command),
164 index_offset, index,
165 length_offset, count))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000166 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700167 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000168 if (err)
169 return err;
170 if (unpack_byte_string(response, response_length, "d",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200171 data_size_offset, &data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000172 return TPM_LIB_ERROR;
173 if (data_size > count)
174 return TPM_LIB_ERROR;
175 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200176 data_offset, data, data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000177 return TPM_LIB_ERROR;
178
179 return 0;
180}
181
Simon Glass8ceca1d2018-11-18 14:22:27 -0700182u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data,
183 u32 length)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000184{
Miquel Raynald790f552018-05-15 11:56:59 +0200185 const u8 command[256] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000186 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
187 };
188 const size_t command_size_offset = 2;
189 const size_t index_offset = 10;
190 const size_t length_offset = 18;
191 const size_t data_offset = 22;
192 const size_t write_info_size = 12;
Miquel Raynald790f552018-05-15 11:56:59 +0200193 const u32 total_length =
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000194 TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
Miquel Raynald790f552018-05-15 11:56:59 +0200195 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000196 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200197 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000198
199 if (pack_byte_string(buf, sizeof(buf), "sddds",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200200 0, command, sizeof(command),
201 command_size_offset, total_length,
202 index_offset, index,
203 length_offset, length,
204 data_offset, data, length))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000205 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700206 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000207 if (err)
208 return err;
209
210 return 0;
211}
212
Simon Glass8ceca1d2018-11-18 14:22:27 -0700213uint32_t tpm_set_global_lock(struct udevice *dev)
Simon Glassbccabbe2018-10-01 12:22:29 -0600214{
Heinrich Schuchardt060aefc2019-02-05 01:38:41 +0100215 return tpm_nv_write_value(dev, TPM_NV_INDEX_0, NULL, 0);
Simon Glassbccabbe2018-10-01 12:22:29 -0600216}
217
Simon Glass8ceca1d2018-11-18 14:22:27 -0700218u32 tpm_extend(struct udevice *dev, u32 index, const void *in_digest,
219 void *out_digest)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000220{
Miquel Raynald790f552018-05-15 11:56:59 +0200221 const u8 command[34] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000222 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
223 };
224 const size_t index_offset = 10;
225 const size_t in_digest_offset = 14;
226 const size_t out_digest_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200227 u8 buf[COMMAND_BUFFER_SIZE];
228 u8 response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000229 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200230 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000231
232 if (pack_byte_string(buf, sizeof(buf), "sds",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200233 0, command, sizeof(command),
234 index_offset, index,
235 in_digest_offset, in_digest,
236 PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000237 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700238 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000239 if (err)
240 return err;
241
242 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200243 out_digest_offset, out_digest,
244 PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000245 return TPM_LIB_ERROR;
246
247 return 0;
248}
249
Simon Glass8ceca1d2018-11-18 14:22:27 -0700250u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000251{
Miquel Raynald790f552018-05-15 11:56:59 +0200252 const u8 command[14] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000253 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
254 };
255 const size_t index_offset = 10;
256 const size_t out_digest_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200257 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000258 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200259 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000260
261 if (count < PCR_DIGEST_LENGTH)
262 return TPM_LIB_ERROR;
263
264 if (pack_byte_string(buf, sizeof(buf), "sd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200265 0, command, sizeof(command),
266 index_offset, index))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000267 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700268 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000269 if (err)
270 return err;
271 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200272 out_digest_offset, data, PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000273 return TPM_LIB_ERROR;
274
275 return 0;
276}
277
Simon Glass8ceca1d2018-11-18 14:22:27 -0700278u32 tpm_tsc_physical_presence(struct udevice *dev, u16 presence)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000279{
Miquel Raynald790f552018-05-15 11:56:59 +0200280 const u8 command[12] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000281 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
282 };
283 const size_t presence_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200284 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000285
286 if (pack_byte_string(buf, sizeof(buf), "sw",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200287 0, command, sizeof(command),
288 presence_offset, presence))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000289 return TPM_LIB_ERROR;
290
Simon Glass8ceca1d2018-11-18 14:22:27 -0700291 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000292}
293
Simon Glass8ceca1d2018-11-18 14:22:27 -0700294u32 tpm_finalise_physical_presence(struct udevice *dev)
Simon Glassbccabbe2018-10-01 12:22:29 -0600295{
296 const u8 command[12] = {
297 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x2, 0xa0,
298 };
299
Simon Glass8ceca1d2018-11-18 14:22:27 -0700300 return tpm_sendrecv_command(dev, command, NULL, NULL);
Simon Glassbccabbe2018-10-01 12:22:29 -0600301}
302
Simon Glass8ceca1d2018-11-18 14:22:27 -0700303u32 tpm_read_pubek(struct udevice *dev, void *data, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000304{
Miquel Raynald790f552018-05-15 11:56:59 +0200305 const u8 command[30] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000306 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
307 };
308 const size_t response_size_offset = 2;
309 const size_t data_offset = 10;
310 const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
Miquel Raynald790f552018-05-15 11:56:59 +0200311 u8 response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000312 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200313 u32 data_size;
314 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000315
Simon Glass8ceca1d2018-11-18 14:22:27 -0700316 err = tpm_sendrecv_command(dev, command, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000317 if (err)
318 return err;
319 if (unpack_byte_string(response, response_length, "d",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200320 response_size_offset, &data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000321 return TPM_LIB_ERROR;
322 if (data_size < header_and_checksum_size)
323 return TPM_LIB_ERROR;
324 data_size -= header_and_checksum_size;
325 if (data_size > count)
326 return TPM_LIB_ERROR;
327 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200328 data_offset, data, data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000329 return TPM_LIB_ERROR;
330
331 return 0;
332}
333
Simon Glass8ceca1d2018-11-18 14:22:27 -0700334u32 tpm_force_clear(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000335{
Miquel Raynald790f552018-05-15 11:56:59 +0200336 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000337 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
338 };
339
Simon Glass8ceca1d2018-11-18 14:22:27 -0700340 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000341}
342
Simon Glass8ceca1d2018-11-18 14:22:27 -0700343u32 tpm_physical_enable(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000344{
Miquel Raynald790f552018-05-15 11:56:59 +0200345 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000346 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
347 };
348
Simon Glass8ceca1d2018-11-18 14:22:27 -0700349 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000350}
351
Simon Glass8ceca1d2018-11-18 14:22:27 -0700352u32 tpm_physical_disable(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000353{
Miquel Raynald790f552018-05-15 11:56:59 +0200354 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000355 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
356 };
357
Simon Glass8ceca1d2018-11-18 14:22:27 -0700358 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000359}
360
Simon Glass8ceca1d2018-11-18 14:22:27 -0700361u32 tpm_physical_set_deactivated(struct udevice *dev, u8 state)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000362{
Miquel Raynald790f552018-05-15 11:56:59 +0200363 const u8 command[11] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000364 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
365 };
366 const size_t state_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200367 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000368
369 if (pack_byte_string(buf, sizeof(buf), "sb",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200370 0, command, sizeof(command),
371 state_offset, state))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000372 return TPM_LIB_ERROR;
373
Simon Glass8ceca1d2018-11-18 14:22:27 -0700374 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000375}
376
Simon Glass8ceca1d2018-11-18 14:22:27 -0700377u32 tpm_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap,
378 void *cap, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000379{
Miquel Raynald790f552018-05-15 11:56:59 +0200380 const u8 command[22] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000381 0x0, 0xc1, /* TPM_TAG */
382 0x0, 0x0, 0x0, 0x16, /* parameter size */
383 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
384 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */
385 0x0, 0x0, 0x0, 0x4, /* subcap size */
386 0x0, 0x0, 0x0, 0x0, /* subcap value */
387 };
388 const size_t cap_area_offset = 10;
389 const size_t sub_cap_offset = 18;
390 const size_t cap_offset = 14;
391 const size_t cap_size_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200392 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000393 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200394 u32 cap_size;
395 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000396
397 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200398 0, command, sizeof(command),
399 cap_area_offset, cap_area,
400 sub_cap_offset, sub_cap))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000401 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700402 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000403 if (err)
404 return err;
405 if (unpack_byte_string(response, response_length, "d",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200406 cap_size_offset, &cap_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000407 return TPM_LIB_ERROR;
408 if (cap_size > response_length || cap_size > count)
409 return TPM_LIB_ERROR;
410 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200411 cap_offset, cap, cap_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000412 return TPM_LIB_ERROR;
413
414 return 0;
415}
Reinhard Pfau4fece432013-06-26 15:55:13 +0200416
Simon Glass8ceca1d2018-11-18 14:22:27 -0700417u32 tpm_get_permanent_flags(struct udevice *dev,
418 struct tpm_permanent_flags *pflags)
Simon Glassff9f04a2015-08-22 18:31:41 -0600419{
Miquel Raynald790f552018-05-15 11:56:59 +0200420 const u8 command[22] = {
Simon Glassff9f04a2015-08-22 18:31:41 -0600421 0x0, 0xc1, /* TPM_TAG */
422 0x0, 0x0, 0x0, 0x16, /* parameter size */
423 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
424 0x0, 0x0, 0x0, 0x4, /* TPM_CAP_FLAG_PERM */
425 0x0, 0x0, 0x0, 0x4, /* subcap size */
426 0x0, 0x0, 0x1, 0x8, /* subcap value */
427 };
André Draszik1361fbc2017-10-03 16:55:51 +0100428 const size_t data_size_offset = TPM_HEADER_SIZE;
Miquel Raynald790f552018-05-15 11:56:59 +0200429 const size_t data_offset = TPM_HEADER_SIZE + sizeof(u32);
430 u8 response[COMMAND_BUFFER_SIZE];
Simon Glassff9f04a2015-08-22 18:31:41 -0600431 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200432 u32 err;
433 u32 data_size;
Simon Glassff9f04a2015-08-22 18:31:41 -0600434
Simon Glass8ceca1d2018-11-18 14:22:27 -0700435 err = tpm_sendrecv_command(dev, command, response, &response_length);
Simon Glassff9f04a2015-08-22 18:31:41 -0600436 if (err)
437 return err;
André Draszik1361fbc2017-10-03 16:55:51 +0100438 if (unpack_byte_string(response, response_length, "d",
Simon Glassbccabbe2018-10-01 12:22:29 -0600439 data_size_offset, &data_size)) {
440 log_err("Cannot unpack data size\n");
André Draszik1361fbc2017-10-03 16:55:51 +0100441 return TPM_LIB_ERROR;
Simon Glassbccabbe2018-10-01 12:22:29 -0600442 }
443 if (data_size < sizeof(*pflags)) {
444 log_err("Data size too small\n");
André Draszik1361fbc2017-10-03 16:55:51 +0100445 return TPM_LIB_ERROR;
Simon Glassbccabbe2018-10-01 12:22:29 -0600446 }
André Draszik1361fbc2017-10-03 16:55:51 +0100447 if (unpack_byte_string(response, response_length, "s",
Simon Glassbccabbe2018-10-01 12:22:29 -0600448 data_offset, pflags, sizeof(*pflags))) {
449 log_err("Cannot unpack pflags\n");
André Draszik1361fbc2017-10-03 16:55:51 +0100450 return TPM_LIB_ERROR;
Simon Glassbccabbe2018-10-01 12:22:29 -0600451 }
Simon Glassff9f04a2015-08-22 18:31:41 -0600452
453 return 0;
454}
455
Simon Glass8ceca1d2018-11-18 14:22:27 -0700456u32 tpm_get_permissions(struct udevice *dev, u32 index, u32 *perm)
Simon Glassff9f04a2015-08-22 18:31:41 -0600457{
Miquel Raynald790f552018-05-15 11:56:59 +0200458 const u8 command[22] = {
Simon Glassff9f04a2015-08-22 18:31:41 -0600459 0x0, 0xc1, /* TPM_TAG */
460 0x0, 0x0, 0x0, 0x16, /* parameter size */
461 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
462 0x0, 0x0, 0x0, 0x11,
463 0x0, 0x0, 0x0, 0x4,
464 };
465 const size_t index_offset = 18;
466 const size_t perm_offset = 60;
Miquel Raynald790f552018-05-15 11:56:59 +0200467 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Simon Glassff9f04a2015-08-22 18:31:41 -0600468 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200469 u32 err;
Simon Glassff9f04a2015-08-22 18:31:41 -0600470
471 if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command),
472 index_offset, index))
473 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700474 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Simon Glassff9f04a2015-08-22 18:31:41 -0600475 if (err)
476 return err;
477 if (unpack_byte_string(response, response_length, "d",
478 perm_offset, perm))
479 return TPM_LIB_ERROR;
480
481 return 0;
482}
483
Mario Six4eceb6c2017-01-11 16:00:50 +0100484#ifdef CONFIG_TPM_FLUSH_RESOURCES
Simon Glass8ceca1d2018-11-18 14:22:27 -0700485u32 tpm_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type)
Mario Six4eceb6c2017-01-11 16:00:50 +0100486{
Miquel Raynald790f552018-05-15 11:56:59 +0200487 const u8 command[18] = {
Mario Six4eceb6c2017-01-11 16:00:50 +0100488 0x00, 0xc1, /* TPM_TAG */
489 0x00, 0x00, 0x00, 0x12, /* parameter size */
490 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
491 0x00, 0x00, 0x00, 0x00, /* key handle */
492 0x00, 0x00, 0x00, 0x00, /* resource type */
493 };
494 const size_t key_handle_offset = 10;
495 const size_t resource_type_offset = 14;
Miquel Raynald790f552018-05-15 11:56:59 +0200496 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Mario Six4eceb6c2017-01-11 16:00:50 +0100497 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200498 u32 err;
Mario Six4eceb6c2017-01-11 16:00:50 +0100499
500 if (pack_byte_string(buf, sizeof(buf), "sdd",
501 0, command, sizeof(command),
502 key_handle_offset, key_handle,
503 resource_type_offset, resource_type))
504 return TPM_LIB_ERROR;
505
Simon Glass8ceca1d2018-11-18 14:22:27 -0700506 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Mario Six4eceb6c2017-01-11 16:00:50 +0100507 if (err)
508 return err;
509 return 0;
510}
511#endif /* CONFIG_TPM_FLUSH_RESOURCES */
512
Reinhard Pfau4fece432013-06-26 15:55:13 +0200513#ifdef CONFIG_TPM_AUTH_SESSIONS
514
515/**
516 * Fill an authentication block in a request.
517 * This func can create the first as well as the second auth block (for
518 * double authorized commands).
519 *
520 * @param request pointer to the request (w/ uninitialised auth data)
521 * @param request_len0 length of the request without auth data
522 * @param handles_len length of the handles area in request
523 * @param auth_session pointer to the (valid) auth session to be used
524 * @param request_auth pointer to the auth block of the request to be filled
525 * @param auth authentication data (HMAC key)
526 */
Miquel Raynald790f552018-05-15 11:56:59 +0200527static u32 create_request_auth(const void *request, size_t request_len0,
528 size_t handles_len,
529 struct session_data *auth_session,
530 void *request_auth, const void *auth)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200531{
Miquel Raynald790f552018-05-15 11:56:59 +0200532 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200533 sha1_context hash_ctx;
534 const size_t command_code_offset = 6;
535 const size_t auth_nonce_odd_offset = 4;
536 const size_t auth_continue_offset = 24;
537 const size_t auth_auth_offset = 25;
538
539 if (!auth_session || !auth_session->valid)
540 return TPM_LIB_ERROR;
541
542 sha1_starts(&hash_ctx);
543 sha1_update(&hash_ctx, request + command_code_offset, 4);
544 if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
545 sha1_update(&hash_ctx,
546 request + TPM_REQUEST_HEADER_LENGTH + handles_len,
547 request_len0 - TPM_REQUEST_HEADER_LENGTH
548 - handles_len);
549 sha1_finish(&hash_ctx, hmac_data);
550
551 sha1_starts(&hash_ctx);
552 sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
553 sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
554 sha1_finish(&hash_ctx, auth_session->nonce_odd);
555
556 if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
557 0, auth_session->handle,
558 auth_nonce_odd_offset, auth_session->nonce_odd,
559 DIGEST_LENGTH,
560 auth_continue_offset, 1))
561 return TPM_LIB_ERROR;
562 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
563 DIGEST_LENGTH,
564 auth_session->nonce_even,
565 DIGEST_LENGTH,
566 2 * DIGEST_LENGTH,
567 request_auth + auth_nonce_odd_offset,
568 DIGEST_LENGTH + 1))
569 return TPM_LIB_ERROR;
570 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
571 request_auth + auth_auth_offset);
572
573 return TPM_SUCCESS;
574}
575
576/**
577 * Verify an authentication block in a response.
578 * Since this func updates the nonce_even in the session data it has to be
579 * called when receiving a succesfull AUTH response.
580 * This func can verify the first as well as the second auth block (for
581 * double authorized commands).
582 *
583 * @param command_code command code of the request
584 * @param response pointer to the request (w/ uninitialised auth data)
585 * @param handles_len length of the handles area in response
586 * @param auth_session pointer to the (valid) auth session to be used
587 * @param response_auth pointer to the auth block of the response to be verified
588 * @param auth authentication data (HMAC key)
589 */
Miquel Raynald790f552018-05-15 11:56:59 +0200590static u32 verify_response_auth(u32 command_code, const void *response,
591 size_t response_len0, size_t handles_len,
592 struct session_data *auth_session,
593 const void *response_auth, const void *auth)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200594{
Miquel Raynald790f552018-05-15 11:56:59 +0200595 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
596 u8 computed_auth[DIGEST_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200597 sha1_context hash_ctx;
598 const size_t return_code_offset = 6;
599 const size_t auth_continue_offset = 20;
600 const size_t auth_auth_offset = 21;
Miquel Raynald790f552018-05-15 11:56:59 +0200601 u8 auth_continue;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200602
603 if (!auth_session || !auth_session->valid)
604 return TPM_AUTHFAIL;
605 if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
606 0, command_code))
607 return TPM_LIB_ERROR;
608 if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
609 return TPM_LIB_ERROR;
610
611 sha1_starts(&hash_ctx);
612 sha1_update(&hash_ctx, response + return_code_offset, 4);
613 sha1_update(&hash_ctx, hmac_data, 4);
614 if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
615 sha1_update(&hash_ctx,
616 response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
617 response_len0 - TPM_RESPONSE_HEADER_LENGTH
618 - handles_len);
619 sha1_finish(&hash_ctx, hmac_data);
620
621 memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
Miquel Raynald790f552018-05-15 11:56:59 +0200622 auth_continue = ((u8 *)response_auth)[auth_continue_offset];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200623 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
624 DIGEST_LENGTH,
625 response_auth,
626 DIGEST_LENGTH,
627 2 * DIGEST_LENGTH,
628 auth_session->nonce_odd,
629 DIGEST_LENGTH,
630 3 * DIGEST_LENGTH,
631 auth_continue))
632 return TPM_LIB_ERROR;
633
634 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
635 computed_auth);
636
637 if (memcmp(computed_auth, response_auth + auth_auth_offset,
638 DIGEST_LENGTH))
639 return TPM_AUTHFAIL;
640
641 return TPM_SUCCESS;
642}
643
Simon Glass8ceca1d2018-11-18 14:22:27 -0700644u32 tpm_terminate_auth_session(struct udevice *dev, u32 auth_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200645{
Miquel Raynald790f552018-05-15 11:56:59 +0200646 const u8 command[18] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200647 0x00, 0xc1, /* TPM_TAG */
648 0x00, 0x00, 0x00, 0x00, /* parameter size */
649 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
650 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
Miquel Raynala59aa342018-05-15 11:57:02 +0200651 0x00, 0x00, 0x00, 0x02, /* TPM_RESOURCE_TYPE */
Reinhard Pfau4fece432013-06-26 15:55:13 +0200652 };
653 const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200654 u8 request[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200655
656 if (pack_byte_string(request, sizeof(request), "sd",
657 0, command, sizeof(command),
658 req_handle_offset, auth_handle))
659 return TPM_LIB_ERROR;
660 if (oiap_session.valid && oiap_session.handle == auth_handle)
661 oiap_session.valid = 0;
662
Simon Glass8ceca1d2018-11-18 14:22:27 -0700663 return tpm_sendrecv_command(dev, request, NULL, NULL);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200664}
665
Simon Glass8ceca1d2018-11-18 14:22:27 -0700666u32 tpm_end_oiap(struct udevice *dev)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200667{
Miquel Raynald790f552018-05-15 11:56:59 +0200668 u32 err = TPM_SUCCESS;
Miquel Raynal82b05662018-05-15 11:57:03 +0200669
Reinhard Pfau4fece432013-06-26 15:55:13 +0200670 if (oiap_session.valid)
Simon Glass8ceca1d2018-11-18 14:22:27 -0700671 err = tpm_terminate_auth_session(dev, oiap_session.handle);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200672 return err;
673}
674
Simon Glass8ceca1d2018-11-18 14:22:27 -0700675u32 tpm_oiap(struct udevice *dev, u32 *auth_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200676{
Miquel Raynald790f552018-05-15 11:56:59 +0200677 const u8 command[10] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200678 0x00, 0xc1, /* TPM_TAG */
679 0x00, 0x00, 0x00, 0x0a, /* parameter size */
680 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
681 };
682 const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
683 const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
Miquel Raynald790f552018-05-15 11:56:59 +0200684 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200685 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200686 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200687
688 if (oiap_session.valid)
Simon Glass8ceca1d2018-11-18 14:22:27 -0700689 tpm_terminate_auth_session(dev, oiap_session.handle);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200690
Simon Glass8ceca1d2018-11-18 14:22:27 -0700691 err = tpm_sendrecv_command(dev, command, response, &response_length);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200692 if (err)
693 return err;
694 if (unpack_byte_string(response, response_length, "ds",
695 res_auth_handle_offset, &oiap_session.handle,
696 res_nonce_even_offset, &oiap_session.nonce_even,
Miquel Raynald790f552018-05-15 11:56:59 +0200697 (u32)DIGEST_LENGTH))
Reinhard Pfau4fece432013-06-26 15:55:13 +0200698 return TPM_LIB_ERROR;
699 oiap_session.valid = 1;
700 if (auth_handle)
701 *auth_handle = oiap_session.handle;
702 return 0;
703}
704
Simon Glass8ceca1d2018-11-18 14:22:27 -0700705u32 tpm_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key,
706 size_t key_length, const void *parent_key_usage_auth,
707 u32 *key_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200708{
Miquel Raynald790f552018-05-15 11:56:59 +0200709 const u8 command[14] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200710 0x00, 0xc2, /* TPM_TAG */
711 0x00, 0x00, 0x00, 0x00, /* parameter size */
712 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
713 0x00, 0x00, 0x00, 0x00, /* parent handle */
714 };
715 const size_t req_size_offset = 2;
716 const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
717 const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
718 const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200719 u8 request[sizeof(command) + TPM_KEY12_MAX_LENGTH +
720 TPM_REQUEST_AUTH_LENGTH];
721 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200722 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200723 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200724
725 if (!oiap_session.valid) {
Simon Glass8ceca1d2018-11-18 14:22:27 -0700726 err = tpm_oiap(dev, NULL);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200727 if (err)
728 return err;
729 }
730 if (pack_byte_string(request, sizeof(request), "sdds",
731 0, command, sizeof(command),
732 req_size_offset,
733 sizeof(command) + key_length
734 + TPM_REQUEST_AUTH_LENGTH,
735 req_parent_handle_offset, parent_handle,
736 req_key_offset, key, key_length
737 ))
738 return TPM_LIB_ERROR;
739
740 err = create_request_auth(request, sizeof(command) + key_length, 4,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200741 &oiap_session,
742 request + sizeof(command) + key_length,
743 parent_key_usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200744 if (err)
745 return err;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700746 err = tpm_sendrecv_command(dev, request, response, &response_length);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200747 if (err) {
748 if (err == TPM_AUTHFAIL)
749 oiap_session.valid = 0;
750 return err;
751 }
752
753 err = verify_response_auth(0x00000041, response,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200754 response_length - TPM_RESPONSE_AUTH_LENGTH,
755 4, &oiap_session,
756 response + response_length -
757 TPM_RESPONSE_AUTH_LENGTH,
758 parent_key_usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200759 if (err)
760 return err;
761
762 if (key_handle) {
763 if (unpack_byte_string(response, response_length, "d",
764 res_handle_offset, key_handle))
765 return TPM_LIB_ERROR;
766 }
767
768 return 0;
769}
770
Simon Glass8ceca1d2018-11-18 14:22:27 -0700771u32 tpm_get_pub_key_oiap(struct udevice *dev, u32 key_handle,
772 const void *usage_auth, void *pubkey,
Miquel Raynald790f552018-05-15 11:56:59 +0200773 size_t *pubkey_len)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200774{
Miquel Raynald790f552018-05-15 11:56:59 +0200775 const u8 command[14] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200776 0x00, 0xc2, /* TPM_TAG */
777 0x00, 0x00, 0x00, 0x00, /* parameter size */
778 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
779 0x00, 0x00, 0x00, 0x00, /* key handle */
780 };
781 const size_t req_size_offset = 2;
782 const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
783 const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200784 u8 request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
785 u8 response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH +
786 TPM_RESPONSE_AUTH_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200787 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200788 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200789
790 if (!oiap_session.valid) {
Simon Glass8ceca1d2018-11-18 14:22:27 -0700791 err = tpm_oiap(dev, NULL);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200792 if (err)
793 return err;
794 }
795 if (pack_byte_string(request, sizeof(request), "sdd",
796 0, command, sizeof(command),
797 req_size_offset,
Miquel Raynald790f552018-05-15 11:56:59 +0200798 (u32)(sizeof(command)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200799 + TPM_REQUEST_AUTH_LENGTH),
800 req_key_handle_offset, key_handle
801 ))
802 return TPM_LIB_ERROR;
803 err = create_request_auth(request, sizeof(command), 4, &oiap_session,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200804 request + sizeof(command), usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200805 if (err)
806 return err;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700807 err = tpm_sendrecv_command(dev, request, response, &response_length);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200808 if (err) {
809 if (err == TPM_AUTHFAIL)
810 oiap_session.valid = 0;
811 return err;
812 }
813 err = verify_response_auth(0x00000021, response,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200814 response_length - TPM_RESPONSE_AUTH_LENGTH,
815 0, &oiap_session,
816 response + response_length -
817 TPM_RESPONSE_AUTH_LENGTH,
818 usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200819 if (err)
820 return err;
821
822 if (pubkey) {
823 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
Miquel Raynal886ccc02018-05-15 11:57:00 +0200824 - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200825 return TPM_LIB_ERROR;
826 *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
827 - TPM_RESPONSE_AUTH_LENGTH;
828 memcpy(pubkey, response + res_pubkey_offset,
829 response_length - TPM_RESPONSE_HEADER_LENGTH
830 - TPM_RESPONSE_AUTH_LENGTH);
831 }
832
833 return 0;
834}
835
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100836#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
Simon Glass8ceca1d2018-11-18 14:22:27 -0700837u32 tpm_find_key_sha1(struct udevice *dev, const u8 auth[20],
838 const u8 pubkey_digest[20], u32 *handle)
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100839{
Miquel Raynald790f552018-05-15 11:56:59 +0200840 u16 key_count;
841 u32 key_handles[10];
842 u8 buf[288];
843 u8 *ptr;
844 u32 err;
845 u8 digest[20];
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100846 size_t buf_len;
847 unsigned int i;
848
849 /* fetch list of already loaded keys in the TPM */
Simon Glass8ceca1d2018-11-18 14:22:27 -0700850 err = tpm_get_capability(dev, TPM_CAP_HANDLE, TPM_RT_KEY, buf,
851 sizeof(buf));
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100852 if (err)
853 return -1;
854 key_count = get_unaligned_be16(buf);
855 ptr = buf + 2;
856 for (i = 0; i < key_count; ++i, ptr += 4)
857 key_handles[i] = get_unaligned_be32(ptr);
858
859 /* now search a(/ the) key which we can access with the given auth */
860 for (i = 0; i < key_count; ++i) {
861 buf_len = sizeof(buf);
862 err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len);
863 if (err && err != TPM_AUTHFAIL)
864 return -1;
865 if (err)
866 continue;
867 sha1_csum(buf, buf_len, digest);
868 if (!memcmp(digest, pubkey_digest, 20)) {
869 *handle = key_handles[i];
870 return 0;
871 }
872 }
873 return 1;
874}
875#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
876
Reinhard Pfau4fece432013-06-26 15:55:13 +0200877#endif /* CONFIG_TPM_AUTH_SESSIONS */
André Draszik2c6e5ff2017-10-03 16:55:52 +0100878
Simon Glass8ceca1d2018-11-18 14:22:27 -0700879u32 tpm_get_random(struct udevice *dev, void *data, u32 count)
André Draszik2c6e5ff2017-10-03 16:55:52 +0100880{
Miquel Raynald790f552018-05-15 11:56:59 +0200881 const u8 command[14] = {
André Draszik2c6e5ff2017-10-03 16:55:52 +0100882 0x0, 0xc1, /* TPM_TAG */
883 0x0, 0x0, 0x0, 0xe, /* parameter size */
884 0x0, 0x0, 0x0, 0x46, /* TPM_COMMAND_CODE */
885 };
886 const size_t length_offset = 10;
887 const size_t data_size_offset = 10;
888 const size_t data_offset = 14;
Miquel Raynald790f552018-05-15 11:56:59 +0200889 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
André Draszik2c6e5ff2017-10-03 16:55:52 +0100890 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200891 u32 data_size;
892 u8 *out = data;
André Draszik2c6e5ff2017-10-03 16:55:52 +0100893
894 while (count > 0) {
Miquel Raynald790f552018-05-15 11:56:59 +0200895 u32 this_bytes = min((size_t)count,
896 sizeof(response) - data_offset);
897 u32 err;
André Draszik2c6e5ff2017-10-03 16:55:52 +0100898
899 if (pack_byte_string(buf, sizeof(buf), "sd",
900 0, command, sizeof(command),
901 length_offset, this_bytes))
902 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700903 err = tpm_sendrecv_command(dev, buf, response,
904 &response_length);
André Draszik2c6e5ff2017-10-03 16:55:52 +0100905 if (err)
906 return err;
907 if (unpack_byte_string(response, response_length, "d",
908 data_size_offset, &data_size))
909 return TPM_LIB_ERROR;
910 if (data_size > count)
911 return TPM_LIB_ERROR;
912 if (unpack_byte_string(response, response_length, "s",
913 data_offset, out, data_size))
914 return TPM_LIB_ERROR;
915
916 count -= data_size;
917 out += data_size;
918 }
919
920 return 0;
921}