blob: 7aecb24f9213eddbb17feea0303f2a933c4f1148 [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
7#include <common.h>
Simon Glass3e4f2fd2015-08-22 18:31:32 -06008#include <dm.h>
Che-liang Chiouc18f9012013-02-28 09:34:57 +00009#include <asm/unaligned.h>
Simon Glass3e4f2fd2015-08-22 18:31:32 -060010#include <u-boot/sha1.h>
Miquel Raynal4c6759e2018-05-15 11:57:06 +020011#include <tpm-common.h>
12#include <tpm-v1.h>
13#include "tpm-utils.h"
Che-liang Chiouc18f9012013-02-28 09:34:57 +000014
Reinhard Pfau4fece432013-06-26 15:55:13 +020015#ifdef CONFIG_TPM_AUTH_SESSIONS
16
17#ifndef CONFIG_SHA1
18#error "TPM_AUTH_SESSIONS require SHA1 to be configured, too"
19#endif /* !CONFIG_SHA1 */
20
21struct session_data {
22 int valid;
Miquel Raynald790f552018-05-15 11:56:59 +020023 u32 handle;
24 u8 nonce_even[DIGEST_LENGTH];
25 u8 nonce_odd[DIGEST_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +020026};
27
28static struct session_data oiap_session = {0, };
29
30#endif /* CONFIG_TPM_AUTH_SESSIONS */
31
Miquel Raynald790f552018-05-15 11:56:59 +020032u32 tpm_startup(enum tpm_startup_type mode)
Che-liang Chiouc18f9012013-02-28 09:34:57 +000033{
Miquel Raynald790f552018-05-15 11:56:59 +020034 const u8 command[12] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +000035 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
36 };
37 const size_t mode_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +020038 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +000039
40 if (pack_byte_string(buf, sizeof(buf), "sw",
Miquel Raynal886ccc02018-05-15 11:57:00 +020041 0, command, sizeof(command),
42 mode_offset, mode))
Che-liang Chiouc18f9012013-02-28 09:34:57 +000043 return TPM_LIB_ERROR;
44
45 return tpm_sendrecv_command(buf, NULL, NULL);
46}
47
Miquel Raynald790f552018-05-15 11:56:59 +020048u32 tpm_self_test_full(void)
Che-liang Chiouc18f9012013-02-28 09:34:57 +000049{
Miquel Raynald790f552018-05-15 11:56:59 +020050 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +000051 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
52 };
53 return tpm_sendrecv_command(command, NULL, NULL);
54}
55
Miquel Raynald790f552018-05-15 11:56:59 +020056u32 tpm_continue_self_test(void)
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, 0x53,
60 };
61 return tpm_sendrecv_command(command, NULL, NULL);
62}
63
Miquel Raynald790f552018-05-15 11:56:59 +020064u32 tpm_nv_define_space(u32 index, u32 perm, u32 size)
Che-liang Chiouc18f9012013-02-28 09:34:57 +000065{
Miquel Raynald790f552018-05-15 11:56:59 +020066 const u8 command[101] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +000067 0x0, 0xc1, /* TPM_TAG */
68 0x0, 0x0, 0x0, 0x65, /* parameter size */
69 0x0, 0x0, 0x0, 0xcc, /* TPM_COMMAND_CODE */
70 /* TPM_NV_DATA_PUBLIC->... */
71 0x0, 0x18, /* ...->TPM_STRUCTURE_TAG */
72 0, 0, 0, 0, /* ...->TPM_NV_INDEX */
73 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
74 0x0, 0x3,
75 0, 0, 0,
76 0x1f,
77 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
78 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
79 0x0, 0x3,
80 0, 0, 0,
81 0x1f,
82 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
83 /* TPM_NV_ATTRIBUTES->... */
84 0x0, 0x17, /* ...->TPM_STRUCTURE_TAG */
85 0, 0, 0, 0, /* ...->attributes */
86 /* End of TPM_NV_ATTRIBUTES */
87 0, /* bReadSTClear */
88 0, /* bWriteSTClear */
89 0, /* bWriteDefine */
90 0, 0, 0, 0, /* size */
91 };
92 const size_t index_offset = 12;
93 const size_t perm_offset = 70;
94 const size_t size_offset = 77;
Miquel Raynald790f552018-05-15 11:56:59 +020095 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +000096
97 if (pack_byte_string(buf, sizeof(buf), "sddd",
Miquel Raynal886ccc02018-05-15 11:57:00 +020098 0, command, sizeof(command),
99 index_offset, index,
100 perm_offset, perm,
101 size_offset, size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000102 return TPM_LIB_ERROR;
103
104 return tpm_sendrecv_command(buf, NULL, NULL);
105}
106
Miquel Raynald790f552018-05-15 11:56:59 +0200107u32 tpm_nv_read_value(u32 index, void *data, u32 count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000108{
Miquel Raynald790f552018-05-15 11:56:59 +0200109 const u8 command[22] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000110 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
111 };
112 const size_t index_offset = 10;
113 const size_t length_offset = 18;
114 const size_t data_size_offset = 10;
115 const size_t data_offset = 14;
Miquel Raynald790f552018-05-15 11:56:59 +0200116 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000117 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200118 u32 data_size;
119 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000120
121 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200122 0, command, sizeof(command),
123 index_offset, index,
124 length_offset, count))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000125 return TPM_LIB_ERROR;
126 err = tpm_sendrecv_command(buf, response, &response_length);
127 if (err)
128 return err;
129 if (unpack_byte_string(response, response_length, "d",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200130 data_size_offset, &data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000131 return TPM_LIB_ERROR;
132 if (data_size > count)
133 return TPM_LIB_ERROR;
134 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200135 data_offset, data, data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000136 return TPM_LIB_ERROR;
137
138 return 0;
139}
140
Miquel Raynald790f552018-05-15 11:56:59 +0200141u32 tpm_nv_write_value(u32 index, const void *data, u32 length)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000142{
Miquel Raynald790f552018-05-15 11:56:59 +0200143 const u8 command[256] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000144 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
145 };
146 const size_t command_size_offset = 2;
147 const size_t index_offset = 10;
148 const size_t length_offset = 18;
149 const size_t data_offset = 22;
150 const size_t write_info_size = 12;
Miquel Raynald790f552018-05-15 11:56:59 +0200151 const u32 total_length =
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000152 TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
Miquel Raynald790f552018-05-15 11:56:59 +0200153 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000154 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200155 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000156
157 if (pack_byte_string(buf, sizeof(buf), "sddds",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200158 0, command, sizeof(command),
159 command_size_offset, total_length,
160 index_offset, index,
161 length_offset, length,
162 data_offset, data, length))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000163 return TPM_LIB_ERROR;
164 err = tpm_sendrecv_command(buf, response, &response_length);
165 if (err)
166 return err;
167
168 return 0;
169}
170
Miquel Raynald790f552018-05-15 11:56:59 +0200171u32 tpm_extend(u32 index, const void *in_digest, void *out_digest)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000172{
Miquel Raynald790f552018-05-15 11:56:59 +0200173 const u8 command[34] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000174 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
175 };
176 const size_t index_offset = 10;
177 const size_t in_digest_offset = 14;
178 const size_t out_digest_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200179 u8 buf[COMMAND_BUFFER_SIZE];
180 u8 response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000181 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200182 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000183
184 if (pack_byte_string(buf, sizeof(buf), "sds",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200185 0, command, sizeof(command),
186 index_offset, index,
187 in_digest_offset, in_digest,
188 PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000189 return TPM_LIB_ERROR;
190 err = tpm_sendrecv_command(buf, response, &response_length);
191 if (err)
192 return err;
193
194 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200195 out_digest_offset, out_digest,
196 PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000197 return TPM_LIB_ERROR;
198
199 return 0;
200}
201
Miquel Raynald790f552018-05-15 11:56:59 +0200202u32 tpm_pcr_read(u32 index, void *data, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000203{
Miquel Raynald790f552018-05-15 11:56:59 +0200204 const u8 command[14] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000205 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
206 };
207 const size_t index_offset = 10;
208 const size_t out_digest_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200209 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000210 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200211 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000212
213 if (count < PCR_DIGEST_LENGTH)
214 return TPM_LIB_ERROR;
215
216 if (pack_byte_string(buf, sizeof(buf), "sd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200217 0, command, sizeof(command),
218 index_offset, index))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000219 return TPM_LIB_ERROR;
220 err = tpm_sendrecv_command(buf, response, &response_length);
221 if (err)
222 return err;
223 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200224 out_digest_offset, data, PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000225 return TPM_LIB_ERROR;
226
227 return 0;
228}
229
Miquel Raynald790f552018-05-15 11:56:59 +0200230u32 tpm_tsc_physical_presence(u16 presence)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000231{
Miquel Raynald790f552018-05-15 11:56:59 +0200232 const u8 command[12] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000233 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
234 };
235 const size_t presence_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200236 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000237
238 if (pack_byte_string(buf, sizeof(buf), "sw",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200239 0, command, sizeof(command),
240 presence_offset, presence))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000241 return TPM_LIB_ERROR;
242
243 return tpm_sendrecv_command(buf, NULL, NULL);
244}
245
Miquel Raynald790f552018-05-15 11:56:59 +0200246u32 tpm_read_pubek(void *data, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000247{
Miquel Raynald790f552018-05-15 11:56:59 +0200248 const u8 command[30] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000249 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
250 };
251 const size_t response_size_offset = 2;
252 const size_t data_offset = 10;
253 const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
Miquel Raynald790f552018-05-15 11:56:59 +0200254 u8 response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000255 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200256 u32 data_size;
257 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000258
259 err = tpm_sendrecv_command(command, response, &response_length);
260 if (err)
261 return err;
262 if (unpack_byte_string(response, response_length, "d",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200263 response_size_offset, &data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000264 return TPM_LIB_ERROR;
265 if (data_size < header_and_checksum_size)
266 return TPM_LIB_ERROR;
267 data_size -= header_and_checksum_size;
268 if (data_size > count)
269 return TPM_LIB_ERROR;
270 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200271 data_offset, data, data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000272 return TPM_LIB_ERROR;
273
274 return 0;
275}
276
Miquel Raynald790f552018-05-15 11:56:59 +0200277u32 tpm_force_clear(void)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000278{
Miquel Raynald790f552018-05-15 11:56:59 +0200279 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000280 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
281 };
282
283 return tpm_sendrecv_command(command, NULL, NULL);
284}
285
Miquel Raynald790f552018-05-15 11:56:59 +0200286u32 tpm_physical_enable(void)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000287{
Miquel Raynald790f552018-05-15 11:56:59 +0200288 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000289 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
290 };
291
292 return tpm_sendrecv_command(command, NULL, NULL);
293}
294
Miquel Raynald790f552018-05-15 11:56:59 +0200295u32 tpm_physical_disable(void)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000296{
Miquel Raynald790f552018-05-15 11:56:59 +0200297 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000298 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
299 };
300
301 return tpm_sendrecv_command(command, NULL, NULL);
302}
303
Miquel Raynald790f552018-05-15 11:56:59 +0200304u32 tpm_physical_set_deactivated(u8 state)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000305{
Miquel Raynald790f552018-05-15 11:56:59 +0200306 const u8 command[11] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000307 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
308 };
309 const size_t state_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200310 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000311
312 if (pack_byte_string(buf, sizeof(buf), "sb",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200313 0, command, sizeof(command),
314 state_offset, state))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000315 return TPM_LIB_ERROR;
316
317 return tpm_sendrecv_command(buf, NULL, NULL);
318}
319
Miquel Raynald790f552018-05-15 11:56:59 +0200320u32 tpm_get_capability(u32 cap_area, u32 sub_cap, void *cap, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000321{
Miquel Raynald790f552018-05-15 11:56:59 +0200322 const u8 command[22] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000323 0x0, 0xc1, /* TPM_TAG */
324 0x0, 0x0, 0x0, 0x16, /* parameter size */
325 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
326 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */
327 0x0, 0x0, 0x0, 0x4, /* subcap size */
328 0x0, 0x0, 0x0, 0x0, /* subcap value */
329 };
330 const size_t cap_area_offset = 10;
331 const size_t sub_cap_offset = 18;
332 const size_t cap_offset = 14;
333 const size_t cap_size_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200334 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000335 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200336 u32 cap_size;
337 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000338
339 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200340 0, command, sizeof(command),
341 cap_area_offset, cap_area,
342 sub_cap_offset, sub_cap))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000343 return TPM_LIB_ERROR;
344 err = tpm_sendrecv_command(buf, response, &response_length);
345 if (err)
346 return err;
347 if (unpack_byte_string(response, response_length, "d",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200348 cap_size_offset, &cap_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000349 return TPM_LIB_ERROR;
350 if (cap_size > response_length || cap_size > count)
351 return TPM_LIB_ERROR;
352 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200353 cap_offset, cap, cap_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000354 return TPM_LIB_ERROR;
355
356 return 0;
357}
Reinhard Pfau4fece432013-06-26 15:55:13 +0200358
Miquel Raynald790f552018-05-15 11:56:59 +0200359u32 tpm_get_permanent_flags(struct tpm_permanent_flags *pflags)
Simon Glassff9f04a2015-08-22 18:31:41 -0600360{
Miquel Raynald790f552018-05-15 11:56:59 +0200361 const u8 command[22] = {
Simon Glassff9f04a2015-08-22 18:31:41 -0600362 0x0, 0xc1, /* TPM_TAG */
363 0x0, 0x0, 0x0, 0x16, /* parameter size */
364 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
365 0x0, 0x0, 0x0, 0x4, /* TPM_CAP_FLAG_PERM */
366 0x0, 0x0, 0x0, 0x4, /* subcap size */
367 0x0, 0x0, 0x1, 0x8, /* subcap value */
368 };
André Draszik1361fbc2017-10-03 16:55:51 +0100369 const size_t data_size_offset = TPM_HEADER_SIZE;
Miquel Raynald790f552018-05-15 11:56:59 +0200370 const size_t data_offset = TPM_HEADER_SIZE + sizeof(u32);
371 u8 response[COMMAND_BUFFER_SIZE];
Simon Glassff9f04a2015-08-22 18:31:41 -0600372 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200373 u32 err;
374 u32 data_size;
Simon Glassff9f04a2015-08-22 18:31:41 -0600375
376 err = tpm_sendrecv_command(command, response, &response_length);
377 if (err)
378 return err;
André Draszik1361fbc2017-10-03 16:55:51 +0100379 if (unpack_byte_string(response, response_length, "d",
380 data_size_offset, &data_size))
381 return TPM_LIB_ERROR;
382 if (data_size < sizeof(*pflags))
383 return TPM_LIB_ERROR;
384 if (unpack_byte_string(response, response_length, "s",
385 data_offset, pflags, sizeof(*pflags)))
386 return TPM_LIB_ERROR;
Simon Glassff9f04a2015-08-22 18:31:41 -0600387
388 return 0;
389}
390
Miquel Raynald790f552018-05-15 11:56:59 +0200391u32 tpm_get_permissions(u32 index, u32 *perm)
Simon Glassff9f04a2015-08-22 18:31:41 -0600392{
Miquel Raynald790f552018-05-15 11:56:59 +0200393 const u8 command[22] = {
Simon Glassff9f04a2015-08-22 18:31:41 -0600394 0x0, 0xc1, /* TPM_TAG */
395 0x0, 0x0, 0x0, 0x16, /* parameter size */
396 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
397 0x0, 0x0, 0x0, 0x11,
398 0x0, 0x0, 0x0, 0x4,
399 };
400 const size_t index_offset = 18;
401 const size_t perm_offset = 60;
Miquel Raynald790f552018-05-15 11:56:59 +0200402 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Simon Glassff9f04a2015-08-22 18:31:41 -0600403 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200404 u32 err;
Simon Glassff9f04a2015-08-22 18:31:41 -0600405
406 if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command),
407 index_offset, index))
408 return TPM_LIB_ERROR;
409 err = tpm_sendrecv_command(buf, response, &response_length);
410 if (err)
411 return err;
412 if (unpack_byte_string(response, response_length, "d",
413 perm_offset, perm))
414 return TPM_LIB_ERROR;
415
416 return 0;
417}
418
Mario Six4eceb6c2017-01-11 16:00:50 +0100419#ifdef CONFIG_TPM_FLUSH_RESOURCES
Miquel Raynald790f552018-05-15 11:56:59 +0200420u32 tpm_flush_specific(u32 key_handle, u32 resource_type)
Mario Six4eceb6c2017-01-11 16:00:50 +0100421{
Miquel Raynald790f552018-05-15 11:56:59 +0200422 const u8 command[18] = {
Mario Six4eceb6c2017-01-11 16:00:50 +0100423 0x00, 0xc1, /* TPM_TAG */
424 0x00, 0x00, 0x00, 0x12, /* parameter size */
425 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
426 0x00, 0x00, 0x00, 0x00, /* key handle */
427 0x00, 0x00, 0x00, 0x00, /* resource type */
428 };
429 const size_t key_handle_offset = 10;
430 const size_t resource_type_offset = 14;
Miquel Raynald790f552018-05-15 11:56:59 +0200431 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Mario Six4eceb6c2017-01-11 16:00:50 +0100432 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200433 u32 err;
Mario Six4eceb6c2017-01-11 16:00:50 +0100434
435 if (pack_byte_string(buf, sizeof(buf), "sdd",
436 0, command, sizeof(command),
437 key_handle_offset, key_handle,
438 resource_type_offset, resource_type))
439 return TPM_LIB_ERROR;
440
441 err = tpm_sendrecv_command(buf, response, &response_length);
442 if (err)
443 return err;
444 return 0;
445}
446#endif /* CONFIG_TPM_FLUSH_RESOURCES */
447
Reinhard Pfau4fece432013-06-26 15:55:13 +0200448#ifdef CONFIG_TPM_AUTH_SESSIONS
449
450/**
451 * Fill an authentication block in a request.
452 * This func can create the first as well as the second auth block (for
453 * double authorized commands).
454 *
455 * @param request pointer to the request (w/ uninitialised auth data)
456 * @param request_len0 length of the request without auth data
457 * @param handles_len length of the handles area in request
458 * @param auth_session pointer to the (valid) auth session to be used
459 * @param request_auth pointer to the auth block of the request to be filled
460 * @param auth authentication data (HMAC key)
461 */
Miquel Raynald790f552018-05-15 11:56:59 +0200462static u32 create_request_auth(const void *request, size_t request_len0,
463 size_t handles_len,
464 struct session_data *auth_session,
465 void *request_auth, const void *auth)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200466{
Miquel Raynald790f552018-05-15 11:56:59 +0200467 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200468 sha1_context hash_ctx;
469 const size_t command_code_offset = 6;
470 const size_t auth_nonce_odd_offset = 4;
471 const size_t auth_continue_offset = 24;
472 const size_t auth_auth_offset = 25;
473
474 if (!auth_session || !auth_session->valid)
475 return TPM_LIB_ERROR;
476
477 sha1_starts(&hash_ctx);
478 sha1_update(&hash_ctx, request + command_code_offset, 4);
479 if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
480 sha1_update(&hash_ctx,
481 request + TPM_REQUEST_HEADER_LENGTH + handles_len,
482 request_len0 - TPM_REQUEST_HEADER_LENGTH
483 - handles_len);
484 sha1_finish(&hash_ctx, hmac_data);
485
486 sha1_starts(&hash_ctx);
487 sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
488 sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
489 sha1_finish(&hash_ctx, auth_session->nonce_odd);
490
491 if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
492 0, auth_session->handle,
493 auth_nonce_odd_offset, auth_session->nonce_odd,
494 DIGEST_LENGTH,
495 auth_continue_offset, 1))
496 return TPM_LIB_ERROR;
497 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
498 DIGEST_LENGTH,
499 auth_session->nonce_even,
500 DIGEST_LENGTH,
501 2 * DIGEST_LENGTH,
502 request_auth + auth_nonce_odd_offset,
503 DIGEST_LENGTH + 1))
504 return TPM_LIB_ERROR;
505 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
506 request_auth + auth_auth_offset);
507
508 return TPM_SUCCESS;
509}
510
511/**
512 * Verify an authentication block in a response.
513 * Since this func updates the nonce_even in the session data it has to be
514 * called when receiving a succesfull AUTH response.
515 * This func can verify the first as well as the second auth block (for
516 * double authorized commands).
517 *
518 * @param command_code command code of the request
519 * @param response pointer to the request (w/ uninitialised auth data)
520 * @param handles_len length of the handles area in response
521 * @param auth_session pointer to the (valid) auth session to be used
522 * @param response_auth pointer to the auth block of the response to be verified
523 * @param auth authentication data (HMAC key)
524 */
Miquel Raynald790f552018-05-15 11:56:59 +0200525static u32 verify_response_auth(u32 command_code, const void *response,
526 size_t response_len0, size_t handles_len,
527 struct session_data *auth_session,
528 const void *response_auth, const void *auth)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200529{
Miquel Raynald790f552018-05-15 11:56:59 +0200530 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
531 u8 computed_auth[DIGEST_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200532 sha1_context hash_ctx;
533 const size_t return_code_offset = 6;
534 const size_t auth_continue_offset = 20;
535 const size_t auth_auth_offset = 21;
Miquel Raynald790f552018-05-15 11:56:59 +0200536 u8 auth_continue;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200537
538 if (!auth_session || !auth_session->valid)
539 return TPM_AUTHFAIL;
540 if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
541 0, command_code))
542 return TPM_LIB_ERROR;
543 if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
544 return TPM_LIB_ERROR;
545
546 sha1_starts(&hash_ctx);
547 sha1_update(&hash_ctx, response + return_code_offset, 4);
548 sha1_update(&hash_ctx, hmac_data, 4);
549 if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
550 sha1_update(&hash_ctx,
551 response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
552 response_len0 - TPM_RESPONSE_HEADER_LENGTH
553 - handles_len);
554 sha1_finish(&hash_ctx, hmac_data);
555
556 memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
Miquel Raynald790f552018-05-15 11:56:59 +0200557 auth_continue = ((u8 *)response_auth)[auth_continue_offset];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200558 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
559 DIGEST_LENGTH,
560 response_auth,
561 DIGEST_LENGTH,
562 2 * DIGEST_LENGTH,
563 auth_session->nonce_odd,
564 DIGEST_LENGTH,
565 3 * DIGEST_LENGTH,
566 auth_continue))
567 return TPM_LIB_ERROR;
568
569 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
570 computed_auth);
571
572 if (memcmp(computed_auth, response_auth + auth_auth_offset,
573 DIGEST_LENGTH))
574 return TPM_AUTHFAIL;
575
576 return TPM_SUCCESS;
577}
578
Miquel Raynald790f552018-05-15 11:56:59 +0200579u32 tpm_terminate_auth_session(u32 auth_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200580{
Miquel Raynald790f552018-05-15 11:56:59 +0200581 const u8 command[18] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200582 0x00, 0xc1, /* TPM_TAG */
583 0x00, 0x00, 0x00, 0x00, /* parameter size */
584 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
585 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
Miquel Raynala59aa342018-05-15 11:57:02 +0200586 0x00, 0x00, 0x00, 0x02, /* TPM_RESOURCE_TYPE */
Reinhard Pfau4fece432013-06-26 15:55:13 +0200587 };
588 const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200589 u8 request[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200590
591 if (pack_byte_string(request, sizeof(request), "sd",
592 0, command, sizeof(command),
593 req_handle_offset, auth_handle))
594 return TPM_LIB_ERROR;
595 if (oiap_session.valid && oiap_session.handle == auth_handle)
596 oiap_session.valid = 0;
597
598 return tpm_sendrecv_command(request, NULL, NULL);
599}
600
Miquel Raynald790f552018-05-15 11:56:59 +0200601u32 tpm_end_oiap(void)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200602{
Miquel Raynald790f552018-05-15 11:56:59 +0200603 u32 err = TPM_SUCCESS;
Miquel Raynal82b05662018-05-15 11:57:03 +0200604
Reinhard Pfau4fece432013-06-26 15:55:13 +0200605 if (oiap_session.valid)
606 err = tpm_terminate_auth_session(oiap_session.handle);
607 return err;
608}
609
Miquel Raynald790f552018-05-15 11:56:59 +0200610u32 tpm_oiap(u32 *auth_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200611{
Miquel Raynald790f552018-05-15 11:56:59 +0200612 const u8 command[10] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200613 0x00, 0xc1, /* TPM_TAG */
614 0x00, 0x00, 0x00, 0x0a, /* parameter size */
615 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
616 };
617 const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
618 const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
Miquel Raynald790f552018-05-15 11:56:59 +0200619 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200620 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200621 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200622
623 if (oiap_session.valid)
624 tpm_terminate_auth_session(oiap_session.handle);
625
626 err = tpm_sendrecv_command(command, response, &response_length);
627 if (err)
628 return err;
629 if (unpack_byte_string(response, response_length, "ds",
630 res_auth_handle_offset, &oiap_session.handle,
631 res_nonce_even_offset, &oiap_session.nonce_even,
Miquel Raynald790f552018-05-15 11:56:59 +0200632 (u32)DIGEST_LENGTH))
Reinhard Pfau4fece432013-06-26 15:55:13 +0200633 return TPM_LIB_ERROR;
634 oiap_session.valid = 1;
635 if (auth_handle)
636 *auth_handle = oiap_session.handle;
637 return 0;
638}
639
Miquel Raynald790f552018-05-15 11:56:59 +0200640u32 tpm_load_key2_oiap(u32 parent_handle, const void *key, size_t key_length,
641 const void *parent_key_usage_auth, u32 *key_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200642{
Miquel Raynald790f552018-05-15 11:56:59 +0200643 const u8 command[14] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200644 0x00, 0xc2, /* TPM_TAG */
645 0x00, 0x00, 0x00, 0x00, /* parameter size */
646 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
647 0x00, 0x00, 0x00, 0x00, /* parent handle */
648 };
649 const size_t req_size_offset = 2;
650 const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
651 const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
652 const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200653 u8 request[sizeof(command) + TPM_KEY12_MAX_LENGTH +
654 TPM_REQUEST_AUTH_LENGTH];
655 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200656 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200657 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200658
659 if (!oiap_session.valid) {
660 err = tpm_oiap(NULL);
661 if (err)
662 return err;
663 }
664 if (pack_byte_string(request, sizeof(request), "sdds",
665 0, command, sizeof(command),
666 req_size_offset,
667 sizeof(command) + key_length
668 + TPM_REQUEST_AUTH_LENGTH,
669 req_parent_handle_offset, parent_handle,
670 req_key_offset, key, key_length
671 ))
672 return TPM_LIB_ERROR;
673
674 err = create_request_auth(request, sizeof(command) + key_length, 4,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200675 &oiap_session,
676 request + sizeof(command) + key_length,
677 parent_key_usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200678 if (err)
679 return err;
680 err = tpm_sendrecv_command(request, response, &response_length);
681 if (err) {
682 if (err == TPM_AUTHFAIL)
683 oiap_session.valid = 0;
684 return err;
685 }
686
687 err = verify_response_auth(0x00000041, response,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200688 response_length - TPM_RESPONSE_AUTH_LENGTH,
689 4, &oiap_session,
690 response + response_length -
691 TPM_RESPONSE_AUTH_LENGTH,
692 parent_key_usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200693 if (err)
694 return err;
695
696 if (key_handle) {
697 if (unpack_byte_string(response, response_length, "d",
698 res_handle_offset, key_handle))
699 return TPM_LIB_ERROR;
700 }
701
702 return 0;
703}
704
Miquel Raynald790f552018-05-15 11:56:59 +0200705u32 tpm_get_pub_key_oiap(u32 key_handle, const void *usage_auth, void *pubkey,
706 size_t *pubkey_len)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200707{
Miquel Raynald790f552018-05-15 11:56:59 +0200708 const u8 command[14] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200709 0x00, 0xc2, /* TPM_TAG */
710 0x00, 0x00, 0x00, 0x00, /* parameter size */
711 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
712 0x00, 0x00, 0x00, 0x00, /* key handle */
713 };
714 const size_t req_size_offset = 2;
715 const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
716 const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200717 u8 request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
718 u8 response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH +
719 TPM_RESPONSE_AUTH_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200720 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200721 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200722
723 if (!oiap_session.valid) {
724 err = tpm_oiap(NULL);
725 if (err)
726 return err;
727 }
728 if (pack_byte_string(request, sizeof(request), "sdd",
729 0, command, sizeof(command),
730 req_size_offset,
Miquel Raynald790f552018-05-15 11:56:59 +0200731 (u32)(sizeof(command)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200732 + TPM_REQUEST_AUTH_LENGTH),
733 req_key_handle_offset, key_handle
734 ))
735 return TPM_LIB_ERROR;
736 err = create_request_auth(request, sizeof(command), 4, &oiap_session,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200737 request + sizeof(command), usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200738 if (err)
739 return err;
740 err = tpm_sendrecv_command(request, response, &response_length);
741 if (err) {
742 if (err == TPM_AUTHFAIL)
743 oiap_session.valid = 0;
744 return err;
745 }
746 err = verify_response_auth(0x00000021, response,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200747 response_length - TPM_RESPONSE_AUTH_LENGTH,
748 0, &oiap_session,
749 response + response_length -
750 TPM_RESPONSE_AUTH_LENGTH,
751 usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200752 if (err)
753 return err;
754
755 if (pubkey) {
756 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
Miquel Raynal886ccc02018-05-15 11:57:00 +0200757 - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200758 return TPM_LIB_ERROR;
759 *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
760 - TPM_RESPONSE_AUTH_LENGTH;
761 memcpy(pubkey, response + res_pubkey_offset,
762 response_length - TPM_RESPONSE_HEADER_LENGTH
763 - TPM_RESPONSE_AUTH_LENGTH);
764 }
765
766 return 0;
767}
768
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100769#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
Miquel Raynald790f552018-05-15 11:56:59 +0200770u32 tpm_find_key_sha1(const u8 auth[20], const u8 pubkey_digest[20],
771 u32 *handle)
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100772{
Miquel Raynald790f552018-05-15 11:56:59 +0200773 u16 key_count;
774 u32 key_handles[10];
775 u8 buf[288];
776 u8 *ptr;
777 u32 err;
778 u8 digest[20];
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100779 size_t buf_len;
780 unsigned int i;
781
782 /* fetch list of already loaded keys in the TPM */
783 err = tpm_get_capability(TPM_CAP_HANDLE, TPM_RT_KEY, buf, sizeof(buf));
784 if (err)
785 return -1;
786 key_count = get_unaligned_be16(buf);
787 ptr = buf + 2;
788 for (i = 0; i < key_count; ++i, ptr += 4)
789 key_handles[i] = get_unaligned_be32(ptr);
790
791 /* now search a(/ the) key which we can access with the given auth */
792 for (i = 0; i < key_count; ++i) {
793 buf_len = sizeof(buf);
794 err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len);
795 if (err && err != TPM_AUTHFAIL)
796 return -1;
797 if (err)
798 continue;
799 sha1_csum(buf, buf_len, digest);
800 if (!memcmp(digest, pubkey_digest, 20)) {
801 *handle = key_handles[i];
802 return 0;
803 }
804 }
805 return 1;
806}
807#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
808
Reinhard Pfau4fece432013-06-26 15:55:13 +0200809#endif /* CONFIG_TPM_AUTH_SESSIONS */
André Draszik2c6e5ff2017-10-03 16:55:52 +0100810
Miquel Raynald790f552018-05-15 11:56:59 +0200811u32 tpm_get_random(void *data, u32 count)
André Draszik2c6e5ff2017-10-03 16:55:52 +0100812{
Miquel Raynald790f552018-05-15 11:56:59 +0200813 const u8 command[14] = {
André Draszik2c6e5ff2017-10-03 16:55:52 +0100814 0x0, 0xc1, /* TPM_TAG */
815 0x0, 0x0, 0x0, 0xe, /* parameter size */
816 0x0, 0x0, 0x0, 0x46, /* TPM_COMMAND_CODE */
817 };
818 const size_t length_offset = 10;
819 const size_t data_size_offset = 10;
820 const size_t data_offset = 14;
Miquel Raynald790f552018-05-15 11:56:59 +0200821 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
André Draszik2c6e5ff2017-10-03 16:55:52 +0100822 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200823 u32 data_size;
824 u8 *out = data;
André Draszik2c6e5ff2017-10-03 16:55:52 +0100825
826 while (count > 0) {
Miquel Raynald790f552018-05-15 11:56:59 +0200827 u32 this_bytes = min((size_t)count,
828 sizeof(response) - data_offset);
829 u32 err;
André Draszik2c6e5ff2017-10-03 16:55:52 +0100830
831 if (pack_byte_string(buf, sizeof(buf), "sd",
832 0, command, sizeof(command),
833 length_offset, this_bytes))
834 return TPM_LIB_ERROR;
835 err = tpm_sendrecv_command(buf, response, &response_length);
836 if (err)
837 return err;
838 if (unpack_byte_string(response, response_length, "d",
839 data_size_offset, &data_size))
840 return TPM_LIB_ERROR;
841 if (data_size > count)
842 return TPM_LIB_ERROR;
843 if (unpack_byte_string(response, response_length, "s",
844 data_offset, out, data_size))
845 return TPM_LIB_ERROR;
846
847 count -= data_size;
848 out += data_size;
849 }
850
851 return 0;
852}