blob: 9d45c3d3bf66a163c86b29617c00dca8c9d0614f [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Che-liang Chiou8732b072013-02-28 09:34:57 +00002/*
3 * Copyright (c) 2013 The Chromium OS Authors.
Reinhard Pfaube6c1522013-06-26 15:55:13 +02004 * Coypright (c) 2013 Guntermann & Drunck GmbH
Che-liang Chiou8732b072013-02-28 09:34:57 +00005 */
6
Simon Glass6e64ec12018-10-01 12:22:29 -06007#define LOG_CATEGORY UCLASS_TPM
8
Che-liang Chiou8732b072013-02-28 09:34:57 +00009#include <common.h>
Simon Glassc8a8c512015-08-22 18:31:32 -060010#include <dm.h>
Che-liang Chiou8732b072013-02-28 09:34:57 +000011#include <asm/unaligned.h>
Simon Glassc8a8c512015-08-22 18:31:32 -060012#include <u-boot/sha1.h>
Miquel Raynald677bfe2018-05-15 11:57:06 +020013#include <tpm-common.h>
14#include <tpm-v1.h>
15#include "tpm-utils.h"
Che-liang Chiou8732b072013-02-28 09:34:57 +000016
Reinhard Pfaube6c1522013-06-26 15:55:13 +020017#ifdef CONFIG_TPM_AUTH_SESSIONS
18
19#ifndef CONFIG_SHA1
20#error "TPM_AUTH_SESSIONS require SHA1 to be configured, too"
21#endif /* !CONFIG_SHA1 */
22
23struct session_data {
24 int valid;
Miquel Raynalb9804e52018-05-15 11:56:59 +020025 u32 handle;
26 u8 nonce_even[DIGEST_LENGTH];
27 u8 nonce_odd[DIGEST_LENGTH];
Reinhard Pfaube6c1522013-06-26 15:55:13 +020028};
29
30static struct session_data oiap_session = {0, };
31
32#endif /* CONFIG_TPM_AUTH_SESSIONS */
33
Miquel Raynalb9804e52018-05-15 11:56:59 +020034u32 tpm_startup(enum tpm_startup_type mode)
Che-liang Chiou8732b072013-02-28 09:34:57 +000035{
Miquel Raynalb9804e52018-05-15 11:56:59 +020036 const u8 command[12] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +000037 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x0,
38 };
39 const size_t mode_offset = 10;
Miquel Raynalb9804e52018-05-15 11:56:59 +020040 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +000041
42 if (pack_byte_string(buf, sizeof(buf), "sw",
Miquel Raynalc6179182018-05-15 11:57:00 +020043 0, command, sizeof(command),
44 mode_offset, mode))
Che-liang Chiou8732b072013-02-28 09:34:57 +000045 return TPM_LIB_ERROR;
46
47 return tpm_sendrecv_command(buf, NULL, NULL);
48}
49
Simon Glass6e64ec12018-10-01 12:22:29 -060050u32 tpm_resume(void)
51{
52 return tpm_startup(TPM_ST_STATE);
53}
54
Miquel Raynalb9804e52018-05-15 11:56:59 +020055u32 tpm_self_test_full(void)
Che-liang Chiou8732b072013-02-28 09:34:57 +000056{
Miquel Raynalb9804e52018-05-15 11:56:59 +020057 const u8 command[10] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +000058 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
59 };
60 return tpm_sendrecv_command(command, NULL, NULL);
61}
62
Miquel Raynalb9804e52018-05-15 11:56:59 +020063u32 tpm_continue_self_test(void)
Che-liang Chiou8732b072013-02-28 09:34:57 +000064{
Miquel Raynalb9804e52018-05-15 11:56:59 +020065 const u8 command[10] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +000066 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
67 };
68 return tpm_sendrecv_command(command, NULL, NULL);
69}
70
Simon Glass6e64ec12018-10-01 12:22:29 -060071u32 tpm_clear_and_reenable(void)
72{
73 u32 ret;
74
75 log_info("TPM: Clear and re-enable\n");
76 ret = tpm_force_clear();
77 if (ret != TPM_SUCCESS) {
78 log_err("Can't initiate a force clear\n");
79 return ret;
80 }
81
82#if IS_ENABLED(CONFIG_TPM_V1)
83 ret = tpm_physical_enable();
84 if (ret != TPM_SUCCESS) {
85 log_err("TPM: Can't set enabled state\n");
86 return ret;
87 }
88
89 ret = tpm_physical_set_deactivated(0);
90 if (ret != TPM_SUCCESS) {
91 log_err("TPM: Can't set deactivated state\n");
92 return ret;
93 }
94#endif
95
96 return TPM_SUCCESS;
97}
98
Miquel Raynalb9804e52018-05-15 11:56:59 +020099u32 tpm_nv_define_space(u32 index, u32 perm, u32 size)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000100{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200101 const u8 command[101] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000102 0x0, 0xc1, /* TPM_TAG */
103 0x0, 0x0, 0x0, 0x65, /* parameter size */
104 0x0, 0x0, 0x0, 0xcc, /* TPM_COMMAND_CODE */
105 /* TPM_NV_DATA_PUBLIC->... */
106 0x0, 0x18, /* ...->TPM_STRUCTURE_TAG */
107 0, 0, 0, 0, /* ...->TPM_NV_INDEX */
108 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
109 0x0, 0x3,
110 0, 0, 0,
111 0x1f,
112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
113 /* TPM_NV_DATA_PUBLIC->TPM_PCR_INFO_SHORT */
114 0x0, 0x3,
115 0, 0, 0,
116 0x1f,
117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
118 /* TPM_NV_ATTRIBUTES->... */
119 0x0, 0x17, /* ...->TPM_STRUCTURE_TAG */
120 0, 0, 0, 0, /* ...->attributes */
121 /* End of TPM_NV_ATTRIBUTES */
122 0, /* bReadSTClear */
123 0, /* bWriteSTClear */
124 0, /* bWriteDefine */
125 0, 0, 0, 0, /* size */
126 };
127 const size_t index_offset = 12;
128 const size_t perm_offset = 70;
129 const size_t size_offset = 77;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200130 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000131
132 if (pack_byte_string(buf, sizeof(buf), "sddd",
Miquel Raynalc6179182018-05-15 11:57:00 +0200133 0, command, sizeof(command),
134 index_offset, index,
135 perm_offset, perm,
136 size_offset, size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000137 return TPM_LIB_ERROR;
138
139 return tpm_sendrecv_command(buf, NULL, NULL);
140}
141
Simon Glass6e64ec12018-10-01 12:22:29 -0600142u32 tpm_nv_set_locked(void)
143{
144 return tpm_nv_define_space(TPM_NV_INDEX_LOCK, 0, 0);
145}
146
Miquel Raynalb9804e52018-05-15 11:56:59 +0200147u32 tpm_nv_read_value(u32 index, void *data, u32 count)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000148{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200149 const u8 command[22] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000150 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf,
151 };
152 const size_t index_offset = 10;
153 const size_t length_offset = 18;
154 const size_t data_size_offset = 10;
155 const size_t data_offset = 14;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200156 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000157 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200158 u32 data_size;
159 u32 err;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000160
161 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynalc6179182018-05-15 11:57:00 +0200162 0, command, sizeof(command),
163 index_offset, index,
164 length_offset, count))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000165 return TPM_LIB_ERROR;
166 err = tpm_sendrecv_command(buf, response, &response_length);
167 if (err)
168 return err;
169 if (unpack_byte_string(response, response_length, "d",
Miquel Raynalc6179182018-05-15 11:57:00 +0200170 data_size_offset, &data_size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000171 return TPM_LIB_ERROR;
172 if (data_size > count)
173 return TPM_LIB_ERROR;
174 if (unpack_byte_string(response, response_length, "s",
Miquel Raynalc6179182018-05-15 11:57:00 +0200175 data_offset, data, data_size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000176 return TPM_LIB_ERROR;
177
178 return 0;
179}
180
Miquel Raynalb9804e52018-05-15 11:56:59 +0200181u32 tpm_nv_write_value(u32 index, const void *data, u32 length)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000182{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200183 const u8 command[256] = {
Che-liang Chiou8732b072013-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 Raynalb9804e52018-05-15 11:56:59 +0200191 const u32 total_length =
Che-liang Chiou8732b072013-02-28 09:34:57 +0000192 TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200193 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000194 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200195 u32 err;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000196
197 if (pack_byte_string(buf, sizeof(buf), "sddds",
Miquel Raynalc6179182018-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 Chiou8732b072013-02-28 09:34:57 +0000203 return TPM_LIB_ERROR;
204 err = tpm_sendrecv_command(buf, response, &response_length);
205 if (err)
206 return err;
207
208 return 0;
209}
210
Simon Glass6e64ec12018-10-01 12:22:29 -0600211uint32_t tpm_set_global_lock(void)
212{
213 u32 x;
214
215 return tpm_nv_write_value(TPM_NV_INDEX_0, (uint8_t *)&x, 0);
216}
217
Miquel Raynalb9804e52018-05-15 11:56:59 +0200218u32 tpm_extend(u32 index, const void *in_digest, void *out_digest)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000219{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200220 const u8 command[34] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000221 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
222 };
223 const size_t index_offset = 10;
224 const size_t in_digest_offset = 14;
225 const size_t out_digest_offset = 10;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200226 u8 buf[COMMAND_BUFFER_SIZE];
227 u8 response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000228 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200229 u32 err;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000230
231 if (pack_byte_string(buf, sizeof(buf), "sds",
Miquel Raynalc6179182018-05-15 11:57:00 +0200232 0, command, sizeof(command),
233 index_offset, index,
234 in_digest_offset, in_digest,
235 PCR_DIGEST_LENGTH))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000236 return TPM_LIB_ERROR;
237 err = tpm_sendrecv_command(buf, response, &response_length);
238 if (err)
239 return err;
240
241 if (unpack_byte_string(response, response_length, "s",
Miquel Raynalc6179182018-05-15 11:57:00 +0200242 out_digest_offset, out_digest,
243 PCR_DIGEST_LENGTH))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000244 return TPM_LIB_ERROR;
245
246 return 0;
247}
248
Miquel Raynalb9804e52018-05-15 11:56:59 +0200249u32 tpm_pcr_read(u32 index, void *data, size_t count)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000250{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200251 const u8 command[14] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000252 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
253 };
254 const size_t index_offset = 10;
255 const size_t out_digest_offset = 10;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200256 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000257 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200258 u32 err;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000259
260 if (count < PCR_DIGEST_LENGTH)
261 return TPM_LIB_ERROR;
262
263 if (pack_byte_string(buf, sizeof(buf), "sd",
Miquel Raynalc6179182018-05-15 11:57:00 +0200264 0, command, sizeof(command),
265 index_offset, index))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000266 return TPM_LIB_ERROR;
267 err = tpm_sendrecv_command(buf, response, &response_length);
268 if (err)
269 return err;
270 if (unpack_byte_string(response, response_length, "s",
Miquel Raynalc6179182018-05-15 11:57:00 +0200271 out_digest_offset, data, PCR_DIGEST_LENGTH))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000272 return TPM_LIB_ERROR;
273
274 return 0;
275}
276
Miquel Raynalb9804e52018-05-15 11:56:59 +0200277u32 tpm_tsc_physical_presence(u16 presence)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000278{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200279 const u8 command[12] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000280 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
281 };
282 const size_t presence_offset = 10;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200283 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000284
285 if (pack_byte_string(buf, sizeof(buf), "sw",
Miquel Raynalc6179182018-05-15 11:57:00 +0200286 0, command, sizeof(command),
287 presence_offset, presence))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000288 return TPM_LIB_ERROR;
289
290 return tpm_sendrecv_command(buf, NULL, NULL);
291}
292
Simon Glass6e64ec12018-10-01 12:22:29 -0600293u32 tpm_finalise_physical_presence(void)
294{
295 const u8 command[12] = {
296 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x2, 0xa0,
297 };
298
299 return tpm_sendrecv_command(command, NULL, NULL);
300}
301
Miquel Raynalb9804e52018-05-15 11:56:59 +0200302u32 tpm_read_pubek(void *data, size_t count)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000303{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200304 const u8 command[30] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000305 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
306 };
307 const size_t response_size_offset = 2;
308 const size_t data_offset = 10;
309 const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200310 u8 response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000311 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200312 u32 data_size;
313 u32 err;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000314
315 err = tpm_sendrecv_command(command, response, &response_length);
316 if (err)
317 return err;
318 if (unpack_byte_string(response, response_length, "d",
Miquel Raynalc6179182018-05-15 11:57:00 +0200319 response_size_offset, &data_size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000320 return TPM_LIB_ERROR;
321 if (data_size < header_and_checksum_size)
322 return TPM_LIB_ERROR;
323 data_size -= header_and_checksum_size;
324 if (data_size > count)
325 return TPM_LIB_ERROR;
326 if (unpack_byte_string(response, response_length, "s",
Miquel Raynalc6179182018-05-15 11:57:00 +0200327 data_offset, data, data_size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000328 return TPM_LIB_ERROR;
329
330 return 0;
331}
332
Miquel Raynalb9804e52018-05-15 11:56:59 +0200333u32 tpm_force_clear(void)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000334{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200335 const u8 command[10] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000336 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
337 };
338
339 return tpm_sendrecv_command(command, NULL, NULL);
340}
341
Miquel Raynalb9804e52018-05-15 11:56:59 +0200342u32 tpm_physical_enable(void)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000343{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200344 const u8 command[10] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000345 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
346 };
347
348 return tpm_sendrecv_command(command, NULL, NULL);
349}
350
Miquel Raynalb9804e52018-05-15 11:56:59 +0200351u32 tpm_physical_disable(void)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000352{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200353 const u8 command[10] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000354 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
355 };
356
357 return tpm_sendrecv_command(command, NULL, NULL);
358}
359
Miquel Raynalb9804e52018-05-15 11:56:59 +0200360u32 tpm_physical_set_deactivated(u8 state)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000361{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200362 const u8 command[11] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000363 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
364 };
365 const size_t state_offset = 10;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200366 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000367
368 if (pack_byte_string(buf, sizeof(buf), "sb",
Miquel Raynalc6179182018-05-15 11:57:00 +0200369 0, command, sizeof(command),
370 state_offset, state))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000371 return TPM_LIB_ERROR;
372
373 return tpm_sendrecv_command(buf, NULL, NULL);
374}
375
Miquel Raynalb9804e52018-05-15 11:56:59 +0200376u32 tpm_get_capability(u32 cap_area, u32 sub_cap, void *cap, size_t count)
Che-liang Chiou8732b072013-02-28 09:34:57 +0000377{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200378 const u8 command[22] = {
Che-liang Chiou8732b072013-02-28 09:34:57 +0000379 0x0, 0xc1, /* TPM_TAG */
380 0x0, 0x0, 0x0, 0x16, /* parameter size */
381 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
382 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */
383 0x0, 0x0, 0x0, 0x4, /* subcap size */
384 0x0, 0x0, 0x0, 0x0, /* subcap value */
385 };
386 const size_t cap_area_offset = 10;
387 const size_t sub_cap_offset = 18;
388 const size_t cap_offset = 14;
389 const size_t cap_size_offset = 10;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200390 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiou8732b072013-02-28 09:34:57 +0000391 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200392 u32 cap_size;
393 u32 err;
Che-liang Chiou8732b072013-02-28 09:34:57 +0000394
395 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynalc6179182018-05-15 11:57:00 +0200396 0, command, sizeof(command),
397 cap_area_offset, cap_area,
398 sub_cap_offset, sub_cap))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000399 return TPM_LIB_ERROR;
400 err = tpm_sendrecv_command(buf, response, &response_length);
401 if (err)
402 return err;
403 if (unpack_byte_string(response, response_length, "d",
Miquel Raynalc6179182018-05-15 11:57:00 +0200404 cap_size_offset, &cap_size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000405 return TPM_LIB_ERROR;
406 if (cap_size > response_length || cap_size > count)
407 return TPM_LIB_ERROR;
408 if (unpack_byte_string(response, response_length, "s",
Miquel Raynalc6179182018-05-15 11:57:00 +0200409 cap_offset, cap, cap_size))
Che-liang Chiou8732b072013-02-28 09:34:57 +0000410 return TPM_LIB_ERROR;
411
412 return 0;
413}
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200414
Miquel Raynalb9804e52018-05-15 11:56:59 +0200415u32 tpm_get_permanent_flags(struct tpm_permanent_flags *pflags)
Simon Glass2132f972015-08-22 18:31:41 -0600416{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200417 const u8 command[22] = {
Simon Glass2132f972015-08-22 18:31:41 -0600418 0x0, 0xc1, /* TPM_TAG */
419 0x0, 0x0, 0x0, 0x16, /* parameter size */
420 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
421 0x0, 0x0, 0x0, 0x4, /* TPM_CAP_FLAG_PERM */
422 0x0, 0x0, 0x0, 0x4, /* subcap size */
423 0x0, 0x0, 0x1, 0x8, /* subcap value */
424 };
André Draszike8155df2017-10-03 16:55:51 +0100425 const size_t data_size_offset = TPM_HEADER_SIZE;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200426 const size_t data_offset = TPM_HEADER_SIZE + sizeof(u32);
427 u8 response[COMMAND_BUFFER_SIZE];
Simon Glass2132f972015-08-22 18:31:41 -0600428 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200429 u32 err;
430 u32 data_size;
Simon Glass2132f972015-08-22 18:31:41 -0600431
432 err = tpm_sendrecv_command(command, response, &response_length);
433 if (err)
434 return err;
André Draszike8155df2017-10-03 16:55:51 +0100435 if (unpack_byte_string(response, response_length, "d",
Simon Glass6e64ec12018-10-01 12:22:29 -0600436 data_size_offset, &data_size)) {
437 log_err("Cannot unpack data size\n");
André Draszike8155df2017-10-03 16:55:51 +0100438 return TPM_LIB_ERROR;
Simon Glass6e64ec12018-10-01 12:22:29 -0600439 }
440 if (data_size < sizeof(*pflags)) {
441 log_err("Data size too small\n");
André Draszike8155df2017-10-03 16:55:51 +0100442 return TPM_LIB_ERROR;
Simon Glass6e64ec12018-10-01 12:22:29 -0600443 }
André Draszike8155df2017-10-03 16:55:51 +0100444 if (unpack_byte_string(response, response_length, "s",
Simon Glass6e64ec12018-10-01 12:22:29 -0600445 data_offset, pflags, sizeof(*pflags))) {
446 log_err("Cannot unpack pflags\n");
André Draszike8155df2017-10-03 16:55:51 +0100447 return TPM_LIB_ERROR;
Simon Glass6e64ec12018-10-01 12:22:29 -0600448 }
Simon Glass2132f972015-08-22 18:31:41 -0600449
450 return 0;
451}
452
Miquel Raynalb9804e52018-05-15 11:56:59 +0200453u32 tpm_get_permissions(u32 index, u32 *perm)
Simon Glass2132f972015-08-22 18:31:41 -0600454{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200455 const u8 command[22] = {
Simon Glass2132f972015-08-22 18:31:41 -0600456 0x0, 0xc1, /* TPM_TAG */
457 0x0, 0x0, 0x0, 0x16, /* parameter size */
458 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
459 0x0, 0x0, 0x0, 0x11,
460 0x0, 0x0, 0x0, 0x4,
461 };
462 const size_t index_offset = 18;
463 const size_t perm_offset = 60;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200464 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Simon Glass2132f972015-08-22 18:31:41 -0600465 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200466 u32 err;
Simon Glass2132f972015-08-22 18:31:41 -0600467
468 if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command),
469 index_offset, index))
470 return TPM_LIB_ERROR;
471 err = tpm_sendrecv_command(buf, response, &response_length);
472 if (err)
473 return err;
474 if (unpack_byte_string(response, response_length, "d",
475 perm_offset, perm))
476 return TPM_LIB_ERROR;
477
478 return 0;
479}
480
Mario Six7690be32017-01-11 16:00:50 +0100481#ifdef CONFIG_TPM_FLUSH_RESOURCES
Miquel Raynalb9804e52018-05-15 11:56:59 +0200482u32 tpm_flush_specific(u32 key_handle, u32 resource_type)
Mario Six7690be32017-01-11 16:00:50 +0100483{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200484 const u8 command[18] = {
Mario Six7690be32017-01-11 16:00:50 +0100485 0x00, 0xc1, /* TPM_TAG */
486 0x00, 0x00, 0x00, 0x12, /* parameter size */
487 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
488 0x00, 0x00, 0x00, 0x00, /* key handle */
489 0x00, 0x00, 0x00, 0x00, /* resource type */
490 };
491 const size_t key_handle_offset = 10;
492 const size_t resource_type_offset = 14;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200493 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Mario Six7690be32017-01-11 16:00:50 +0100494 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200495 u32 err;
Mario Six7690be32017-01-11 16:00:50 +0100496
497 if (pack_byte_string(buf, sizeof(buf), "sdd",
498 0, command, sizeof(command),
499 key_handle_offset, key_handle,
500 resource_type_offset, resource_type))
501 return TPM_LIB_ERROR;
502
503 err = tpm_sendrecv_command(buf, response, &response_length);
504 if (err)
505 return err;
506 return 0;
507}
508#endif /* CONFIG_TPM_FLUSH_RESOURCES */
509
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200510#ifdef CONFIG_TPM_AUTH_SESSIONS
511
512/**
513 * Fill an authentication block in a request.
514 * This func can create the first as well as the second auth block (for
515 * double authorized commands).
516 *
517 * @param request pointer to the request (w/ uninitialised auth data)
518 * @param request_len0 length of the request without auth data
519 * @param handles_len length of the handles area in request
520 * @param auth_session pointer to the (valid) auth session to be used
521 * @param request_auth pointer to the auth block of the request to be filled
522 * @param auth authentication data (HMAC key)
523 */
Miquel Raynalb9804e52018-05-15 11:56:59 +0200524static u32 create_request_auth(const void *request, size_t request_len0,
525 size_t handles_len,
526 struct session_data *auth_session,
527 void *request_auth, const void *auth)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200528{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200529 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200530 sha1_context hash_ctx;
531 const size_t command_code_offset = 6;
532 const size_t auth_nonce_odd_offset = 4;
533 const size_t auth_continue_offset = 24;
534 const size_t auth_auth_offset = 25;
535
536 if (!auth_session || !auth_session->valid)
537 return TPM_LIB_ERROR;
538
539 sha1_starts(&hash_ctx);
540 sha1_update(&hash_ctx, request + command_code_offset, 4);
541 if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
542 sha1_update(&hash_ctx,
543 request + TPM_REQUEST_HEADER_LENGTH + handles_len,
544 request_len0 - TPM_REQUEST_HEADER_LENGTH
545 - handles_len);
546 sha1_finish(&hash_ctx, hmac_data);
547
548 sha1_starts(&hash_ctx);
549 sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
550 sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
551 sha1_finish(&hash_ctx, auth_session->nonce_odd);
552
553 if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
554 0, auth_session->handle,
555 auth_nonce_odd_offset, auth_session->nonce_odd,
556 DIGEST_LENGTH,
557 auth_continue_offset, 1))
558 return TPM_LIB_ERROR;
559 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
560 DIGEST_LENGTH,
561 auth_session->nonce_even,
562 DIGEST_LENGTH,
563 2 * DIGEST_LENGTH,
564 request_auth + auth_nonce_odd_offset,
565 DIGEST_LENGTH + 1))
566 return TPM_LIB_ERROR;
567 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
568 request_auth + auth_auth_offset);
569
570 return TPM_SUCCESS;
571}
572
573/**
574 * Verify an authentication block in a response.
575 * Since this func updates the nonce_even in the session data it has to be
576 * called when receiving a succesfull AUTH response.
577 * This func can verify the first as well as the second auth block (for
578 * double authorized commands).
579 *
580 * @param command_code command code of the request
581 * @param response pointer to the request (w/ uninitialised auth data)
582 * @param handles_len length of the handles area in response
583 * @param auth_session pointer to the (valid) auth session to be used
584 * @param response_auth pointer to the auth block of the response to be verified
585 * @param auth authentication data (HMAC key)
586 */
Miquel Raynalb9804e52018-05-15 11:56:59 +0200587static u32 verify_response_auth(u32 command_code, const void *response,
588 size_t response_len0, size_t handles_len,
589 struct session_data *auth_session,
590 const void *response_auth, const void *auth)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200591{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200592 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
593 u8 computed_auth[DIGEST_LENGTH];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200594 sha1_context hash_ctx;
595 const size_t return_code_offset = 6;
596 const size_t auth_continue_offset = 20;
597 const size_t auth_auth_offset = 21;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200598 u8 auth_continue;
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200599
600 if (!auth_session || !auth_session->valid)
601 return TPM_AUTHFAIL;
602 if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
603 0, command_code))
604 return TPM_LIB_ERROR;
605 if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
606 return TPM_LIB_ERROR;
607
608 sha1_starts(&hash_ctx);
609 sha1_update(&hash_ctx, response + return_code_offset, 4);
610 sha1_update(&hash_ctx, hmac_data, 4);
611 if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
612 sha1_update(&hash_ctx,
613 response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
614 response_len0 - TPM_RESPONSE_HEADER_LENGTH
615 - handles_len);
616 sha1_finish(&hash_ctx, hmac_data);
617
618 memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200619 auth_continue = ((u8 *)response_auth)[auth_continue_offset];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200620 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
621 DIGEST_LENGTH,
622 response_auth,
623 DIGEST_LENGTH,
624 2 * DIGEST_LENGTH,
625 auth_session->nonce_odd,
626 DIGEST_LENGTH,
627 3 * DIGEST_LENGTH,
628 auth_continue))
629 return TPM_LIB_ERROR;
630
631 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
632 computed_auth);
633
634 if (memcmp(computed_auth, response_auth + auth_auth_offset,
635 DIGEST_LENGTH))
636 return TPM_AUTHFAIL;
637
638 return TPM_SUCCESS;
639}
640
Miquel Raynalb9804e52018-05-15 11:56:59 +0200641u32 tpm_terminate_auth_session(u32 auth_handle)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200642{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200643 const u8 command[18] = {
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200644 0x00, 0xc1, /* TPM_TAG */
645 0x00, 0x00, 0x00, 0x00, /* parameter size */
646 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
647 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
Miquel Raynal52da18a2018-05-15 11:57:02 +0200648 0x00, 0x00, 0x00, 0x02, /* TPM_RESOURCE_TYPE */
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200649 };
650 const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200651 u8 request[COMMAND_BUFFER_SIZE];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200652
653 if (pack_byte_string(request, sizeof(request), "sd",
654 0, command, sizeof(command),
655 req_handle_offset, auth_handle))
656 return TPM_LIB_ERROR;
657 if (oiap_session.valid && oiap_session.handle == auth_handle)
658 oiap_session.valid = 0;
659
660 return tpm_sendrecv_command(request, NULL, NULL);
661}
662
Miquel Raynalb9804e52018-05-15 11:56:59 +0200663u32 tpm_end_oiap(void)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200664{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200665 u32 err = TPM_SUCCESS;
Miquel Raynal96cc4e32018-05-15 11:57:03 +0200666
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200667 if (oiap_session.valid)
668 err = tpm_terminate_auth_session(oiap_session.handle);
669 return err;
670}
671
Miquel Raynalb9804e52018-05-15 11:56:59 +0200672u32 tpm_oiap(u32 *auth_handle)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200673{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200674 const u8 command[10] = {
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200675 0x00, 0xc1, /* TPM_TAG */
676 0x00, 0x00, 0x00, 0x0a, /* parameter size */
677 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
678 };
679 const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
680 const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200681 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200682 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200683 u32 err;
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200684
685 if (oiap_session.valid)
686 tpm_terminate_auth_session(oiap_session.handle);
687
688 err = tpm_sendrecv_command(command, response, &response_length);
689 if (err)
690 return err;
691 if (unpack_byte_string(response, response_length, "ds",
692 res_auth_handle_offset, &oiap_session.handle,
693 res_nonce_even_offset, &oiap_session.nonce_even,
Miquel Raynalb9804e52018-05-15 11:56:59 +0200694 (u32)DIGEST_LENGTH))
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200695 return TPM_LIB_ERROR;
696 oiap_session.valid = 1;
697 if (auth_handle)
698 *auth_handle = oiap_session.handle;
699 return 0;
700}
701
Miquel Raynalb9804e52018-05-15 11:56:59 +0200702u32 tpm_load_key2_oiap(u32 parent_handle, const void *key, size_t key_length,
703 const void *parent_key_usage_auth, u32 *key_handle)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200704{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200705 const u8 command[14] = {
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200706 0x00, 0xc2, /* TPM_TAG */
707 0x00, 0x00, 0x00, 0x00, /* parameter size */
708 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
709 0x00, 0x00, 0x00, 0x00, /* parent handle */
710 };
711 const size_t req_size_offset = 2;
712 const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
713 const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
714 const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200715 u8 request[sizeof(command) + TPM_KEY12_MAX_LENGTH +
716 TPM_REQUEST_AUTH_LENGTH];
717 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200718 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200719 u32 err;
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200720
721 if (!oiap_session.valid) {
722 err = tpm_oiap(NULL);
723 if (err)
724 return err;
725 }
726 if (pack_byte_string(request, sizeof(request), "sdds",
727 0, command, sizeof(command),
728 req_size_offset,
729 sizeof(command) + key_length
730 + TPM_REQUEST_AUTH_LENGTH,
731 req_parent_handle_offset, parent_handle,
732 req_key_offset, key, key_length
733 ))
734 return TPM_LIB_ERROR;
735
736 err = create_request_auth(request, sizeof(command) + key_length, 4,
Miquel Raynalc6179182018-05-15 11:57:00 +0200737 &oiap_session,
738 request + sizeof(command) + key_length,
739 parent_key_usage_auth);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200740 if (err)
741 return err;
742 err = tpm_sendrecv_command(request, response, &response_length);
743 if (err) {
744 if (err == TPM_AUTHFAIL)
745 oiap_session.valid = 0;
746 return err;
747 }
748
749 err = verify_response_auth(0x00000041, response,
Miquel Raynalc6179182018-05-15 11:57:00 +0200750 response_length - TPM_RESPONSE_AUTH_LENGTH,
751 4, &oiap_session,
752 response + response_length -
753 TPM_RESPONSE_AUTH_LENGTH,
754 parent_key_usage_auth);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200755 if (err)
756 return err;
757
758 if (key_handle) {
759 if (unpack_byte_string(response, response_length, "d",
760 res_handle_offset, key_handle))
761 return TPM_LIB_ERROR;
762 }
763
764 return 0;
765}
766
Miquel Raynalb9804e52018-05-15 11:56:59 +0200767u32 tpm_get_pub_key_oiap(u32 key_handle, const void *usage_auth, void *pubkey,
768 size_t *pubkey_len)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200769{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200770 const u8 command[14] = {
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200771 0x00, 0xc2, /* TPM_TAG */
772 0x00, 0x00, 0x00, 0x00, /* parameter size */
773 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
774 0x00, 0x00, 0x00, 0x00, /* key handle */
775 };
776 const size_t req_size_offset = 2;
777 const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
778 const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200779 u8 request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
780 u8 response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH +
781 TPM_RESPONSE_AUTH_LENGTH];
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200782 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200783 u32 err;
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200784
785 if (!oiap_session.valid) {
786 err = tpm_oiap(NULL);
787 if (err)
788 return err;
789 }
790 if (pack_byte_string(request, sizeof(request), "sdd",
791 0, command, sizeof(command),
792 req_size_offset,
Miquel Raynalb9804e52018-05-15 11:56:59 +0200793 (u32)(sizeof(command)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200794 + TPM_REQUEST_AUTH_LENGTH),
795 req_key_handle_offset, key_handle
796 ))
797 return TPM_LIB_ERROR;
798 err = create_request_auth(request, sizeof(command), 4, &oiap_session,
Miquel Raynalc6179182018-05-15 11:57:00 +0200799 request + sizeof(command), usage_auth);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200800 if (err)
801 return err;
802 err = tpm_sendrecv_command(request, response, &response_length);
803 if (err) {
804 if (err == TPM_AUTHFAIL)
805 oiap_session.valid = 0;
806 return err;
807 }
808 err = verify_response_auth(0x00000021, response,
Miquel Raynalc6179182018-05-15 11:57:00 +0200809 response_length - TPM_RESPONSE_AUTH_LENGTH,
810 0, &oiap_session,
811 response + response_length -
812 TPM_RESPONSE_AUTH_LENGTH,
813 usage_auth);
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200814 if (err)
815 return err;
816
817 if (pubkey) {
818 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
Miquel Raynalc6179182018-05-15 11:57:00 +0200819 - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200820 return TPM_LIB_ERROR;
821 *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
822 - TPM_RESPONSE_AUTH_LENGTH;
823 memcpy(pubkey, response + res_pubkey_offset,
824 response_length - TPM_RESPONSE_HEADER_LENGTH
825 - TPM_RESPONSE_AUTH_LENGTH);
826 }
827
828 return 0;
829}
830
mario.six@gdsys.cc0f4b2ba2017-03-20 10:28:28 +0100831#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
Miquel Raynalb9804e52018-05-15 11:56:59 +0200832u32 tpm_find_key_sha1(const u8 auth[20], const u8 pubkey_digest[20],
833 u32 *handle)
mario.six@gdsys.cc0f4b2ba2017-03-20 10:28:28 +0100834{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200835 u16 key_count;
836 u32 key_handles[10];
837 u8 buf[288];
838 u8 *ptr;
839 u32 err;
840 u8 digest[20];
mario.six@gdsys.cc0f4b2ba2017-03-20 10:28:28 +0100841 size_t buf_len;
842 unsigned int i;
843
844 /* fetch list of already loaded keys in the TPM */
845 err = tpm_get_capability(TPM_CAP_HANDLE, TPM_RT_KEY, buf, sizeof(buf));
846 if (err)
847 return -1;
848 key_count = get_unaligned_be16(buf);
849 ptr = buf + 2;
850 for (i = 0; i < key_count; ++i, ptr += 4)
851 key_handles[i] = get_unaligned_be32(ptr);
852
853 /* now search a(/ the) key which we can access with the given auth */
854 for (i = 0; i < key_count; ++i) {
855 buf_len = sizeof(buf);
856 err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len);
857 if (err && err != TPM_AUTHFAIL)
858 return -1;
859 if (err)
860 continue;
861 sha1_csum(buf, buf_len, digest);
862 if (!memcmp(digest, pubkey_digest, 20)) {
863 *handle = key_handles[i];
864 return 0;
865 }
866 }
867 return 1;
868}
869#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
870
Reinhard Pfaube6c1522013-06-26 15:55:13 +0200871#endif /* CONFIG_TPM_AUTH_SESSIONS */
André Draszik3c605022017-10-03 16:55:52 +0100872
Miquel Raynalb9804e52018-05-15 11:56:59 +0200873u32 tpm_get_random(void *data, u32 count)
André Draszik3c605022017-10-03 16:55:52 +0100874{
Miquel Raynalb9804e52018-05-15 11:56:59 +0200875 const u8 command[14] = {
André Draszik3c605022017-10-03 16:55:52 +0100876 0x0, 0xc1, /* TPM_TAG */
877 0x0, 0x0, 0x0, 0xe, /* parameter size */
878 0x0, 0x0, 0x0, 0x46, /* TPM_COMMAND_CODE */
879 };
880 const size_t length_offset = 10;
881 const size_t data_size_offset = 10;
882 const size_t data_offset = 14;
Miquel Raynalb9804e52018-05-15 11:56:59 +0200883 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
André Draszik3c605022017-10-03 16:55:52 +0100884 size_t response_length = sizeof(response);
Miquel Raynalb9804e52018-05-15 11:56:59 +0200885 u32 data_size;
886 u8 *out = data;
André Draszik3c605022017-10-03 16:55:52 +0100887
888 while (count > 0) {
Miquel Raynalb9804e52018-05-15 11:56:59 +0200889 u32 this_bytes = min((size_t)count,
890 sizeof(response) - data_offset);
891 u32 err;
André Draszik3c605022017-10-03 16:55:52 +0100892
893 if (pack_byte_string(buf, sizeof(buf), "sd",
894 0, command, sizeof(command),
895 length_offset, this_bytes))
896 return TPM_LIB_ERROR;
897 err = tpm_sendrecv_command(buf, response, &response_length);
898 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}