blob: 3e89f8454410869758809660713b7012f6ab6a57 [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>
Che-liang Chiouc18f9012013-02-28 09:34:57 +000011#include <asm/unaligned.h>
Simon Glass3e4f2fd2015-08-22 18:31:32 -060012#include <u-boot/sha1.h>
Miquel Raynal4c6759e2018-05-15 11:57:06 +020013#include <tpm-common.h>
14#include <tpm-v1.h>
15#include "tpm-utils.h"
Che-liang Chiouc18f9012013-02-28 09:34:57 +000016
Reinhard Pfau4fece432013-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 Raynald790f552018-05-15 11:56:59 +020025 u32 handle;
26 u8 nonce_even[DIGEST_LENGTH];
27 u8 nonce_odd[DIGEST_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +020028};
29
30static struct session_data oiap_session = {0, };
31
32#endif /* CONFIG_TPM_AUTH_SESSIONS */
33
Simon Glass8ceca1d2018-11-18 14:22:27 -070034u32 tpm_startup(struct udevice *dev, enum tpm_startup_type mode)
Che-liang Chiouc18f9012013-02-28 09:34:57 +000035{
Miquel Raynald790f552018-05-15 11:56:59 +020036 const u8 command[12] = {
Che-liang Chiouc18f9012013-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 Raynald790f552018-05-15 11:56:59 +020040 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +000041
42 if (pack_byte_string(buf, sizeof(buf), "sw",
Miquel Raynal886ccc02018-05-15 11:57:00 +020043 0, command, sizeof(command),
44 mode_offset, mode))
Che-liang Chiouc18f9012013-02-28 09:34:57 +000045 return TPM_LIB_ERROR;
46
Simon Glass8ceca1d2018-11-18 14:22:27 -070047 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +000048}
49
Simon Glass8ceca1d2018-11-18 14:22:27 -070050u32 tpm_resume(struct udevice *dev)
Simon Glassbccabbe2018-10-01 12:22:29 -060051{
Simon Glass8ceca1d2018-11-18 14:22:27 -070052 return tpm_startup(dev, TPM_ST_STATE);
Simon Glassbccabbe2018-10-01 12:22:29 -060053}
54
Simon Glass8ceca1d2018-11-18 14:22:27 -070055u32 tpm_self_test_full(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +000056{
Miquel Raynald790f552018-05-15 11:56:59 +020057 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +000058 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50,
59 };
Simon Glass8ceca1d2018-11-18 14:22:27 -070060 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +000061}
62
Simon Glass8ceca1d2018-11-18 14:22:27 -070063u32 tpm_continue_self_test(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +000064{
Miquel Raynald790f552018-05-15 11:56:59 +020065 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +000066 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53,
67 };
Simon Glass8ceca1d2018-11-18 14:22:27 -070068 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +000069}
70
Simon Glass8ceca1d2018-11-18 14:22:27 -070071u32 tpm_clear_and_reenable(struct udevice *dev)
Simon Glassbccabbe2018-10-01 12:22:29 -060072{
73 u32 ret;
74
75 log_info("TPM: Clear and re-enable\n");
Simon Glass8ceca1d2018-11-18 14:22:27 -070076 ret = tpm_force_clear(dev);
Simon Glassbccabbe2018-10-01 12:22:29 -060077 if (ret != TPM_SUCCESS) {
78 log_err("Can't initiate a force clear\n");
79 return ret;
80 }
81
Simon Glasse03dbde2018-11-23 21:29:32 -070082 if (tpm_get_version(dev) == TPM_V1) {
83 ret = tpm_physical_enable(dev);
84 if (ret != TPM_SUCCESS) {
85 log_err("TPM: Can't set enabled state\n");
86 return ret;
87 }
Simon Glassbccabbe2018-10-01 12:22:29 -060088
Simon Glasse03dbde2018-11-23 21:29:32 -070089 ret = tpm_physical_set_deactivated(dev, 0);
90 if (ret != TPM_SUCCESS) {
91 log_err("TPM: Can't set deactivated state\n");
92 return ret;
93 }
Simon Glassbccabbe2018-10-01 12:22:29 -060094 }
Simon Glassbccabbe2018-10-01 12:22:29 -060095
96 return TPM_SUCCESS;
97}
98
Simon Glass8ceca1d2018-11-18 14:22:27 -070099u32 tpm_nv_define_space(struct udevice *dev, u32 index, u32 perm, u32 size)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000100{
Miquel Raynald790f552018-05-15 11:56:59 +0200101 const u8 command[101] = {
Che-liang Chiouc18f9012013-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 Raynald790f552018-05-15 11:56:59 +0200130 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000131
132 if (pack_byte_string(buf, sizeof(buf), "sddd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200133 0, command, sizeof(command),
134 index_offset, index,
135 perm_offset, perm,
136 size_offset, size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000137 return TPM_LIB_ERROR;
138
Simon Glass8ceca1d2018-11-18 14:22:27 -0700139 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000140}
141
Simon Glass8ceca1d2018-11-18 14:22:27 -0700142u32 tpm_nv_set_locked(struct udevice *dev)
Simon Glassbccabbe2018-10-01 12:22:29 -0600143{
Simon Glass8ceca1d2018-11-18 14:22:27 -0700144 return tpm_nv_define_space(dev, TPM_NV_INDEX_LOCK, 0, 0);
Simon Glassbccabbe2018-10-01 12:22:29 -0600145}
146
Simon Glass8ceca1d2018-11-18 14:22:27 -0700147u32 tpm_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000148{
Miquel Raynald790f552018-05-15 11:56:59 +0200149 const u8 command[22] = {
Che-liang Chiouc18f9012013-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 Raynald790f552018-05-15 11:56:59 +0200156 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000157 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200158 u32 data_size;
159 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000160
161 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200162 0, command, sizeof(command),
163 index_offset, index,
164 length_offset, count))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000165 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700166 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000167 if (err)
168 return err;
169 if (unpack_byte_string(response, response_length, "d",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200170 data_size_offset, &data_size))
Che-liang Chiouc18f9012013-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 Raynal886ccc02018-05-15 11:57:00 +0200175 data_offset, data, data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000176 return TPM_LIB_ERROR;
177
178 return 0;
179}
180
Simon Glass8ceca1d2018-11-18 14:22:27 -0700181u32 tpm_nv_write_value(struct udevice *dev, u32 index, const void *data,
182 u32 length)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000183{
Miquel Raynald790f552018-05-15 11:56:59 +0200184 const u8 command[256] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000185 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd,
186 };
187 const size_t command_size_offset = 2;
188 const size_t index_offset = 10;
189 const size_t length_offset = 18;
190 const size_t data_offset = 22;
191 const size_t write_info_size = 12;
Miquel Raynald790f552018-05-15 11:56:59 +0200192 const u32 total_length =
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000193 TPM_REQUEST_HEADER_LENGTH + write_info_size + length;
Miquel Raynald790f552018-05-15 11:56:59 +0200194 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000195 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200196 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000197
198 if (pack_byte_string(buf, sizeof(buf), "sddds",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200199 0, command, sizeof(command),
200 command_size_offset, total_length,
201 index_offset, index,
202 length_offset, length,
203 data_offset, data, length))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000204 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700205 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000206 if (err)
207 return err;
208
209 return 0;
210}
211
Simon Glass8ceca1d2018-11-18 14:22:27 -0700212uint32_t tpm_set_global_lock(struct udevice *dev)
Simon Glassbccabbe2018-10-01 12:22:29 -0600213{
214 u32 x;
215
Simon Glass8ceca1d2018-11-18 14:22:27 -0700216 return tpm_nv_write_value(dev, TPM_NV_INDEX_0, (uint8_t *)&x, 0);
Simon Glassbccabbe2018-10-01 12:22:29 -0600217}
218
Simon Glass8ceca1d2018-11-18 14:22:27 -0700219u32 tpm_extend(struct udevice *dev, u32 index, const void *in_digest,
220 void *out_digest)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000221{
Miquel Raynald790f552018-05-15 11:56:59 +0200222 const u8 command[34] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000223 0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14,
224 };
225 const size_t index_offset = 10;
226 const size_t in_digest_offset = 14;
227 const size_t out_digest_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200228 u8 buf[COMMAND_BUFFER_SIZE];
229 u8 response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000230 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200231 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000232
233 if (pack_byte_string(buf, sizeof(buf), "sds",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200234 0, command, sizeof(command),
235 index_offset, index,
236 in_digest_offset, in_digest,
237 PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000238 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700239 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000240 if (err)
241 return err;
242
243 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200244 out_digest_offset, out_digest,
245 PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000246 return TPM_LIB_ERROR;
247
248 return 0;
249}
250
Simon Glass8ceca1d2018-11-18 14:22:27 -0700251u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000252{
Miquel Raynald790f552018-05-15 11:56:59 +0200253 const u8 command[14] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000254 0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15,
255 };
256 const size_t index_offset = 10;
257 const size_t out_digest_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200258 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000259 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200260 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000261
262 if (count < PCR_DIGEST_LENGTH)
263 return TPM_LIB_ERROR;
264
265 if (pack_byte_string(buf, sizeof(buf), "sd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200266 0, command, sizeof(command),
267 index_offset, index))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000268 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700269 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000270 if (err)
271 return err;
272 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200273 out_digest_offset, data, PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000274 return TPM_LIB_ERROR;
275
276 return 0;
277}
278
Simon Glass8ceca1d2018-11-18 14:22:27 -0700279u32 tpm_tsc_physical_presence(struct udevice *dev, u16 presence)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000280{
Miquel Raynald790f552018-05-15 11:56:59 +0200281 const u8 command[12] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000282 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x0,
283 };
284 const size_t presence_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200285 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000286
287 if (pack_byte_string(buf, sizeof(buf), "sw",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200288 0, command, sizeof(command),
289 presence_offset, presence))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000290 return TPM_LIB_ERROR;
291
Simon Glass8ceca1d2018-11-18 14:22:27 -0700292 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000293}
294
Simon Glass8ceca1d2018-11-18 14:22:27 -0700295u32 tpm_finalise_physical_presence(struct udevice *dev)
Simon Glassbccabbe2018-10-01 12:22:29 -0600296{
297 const u8 command[12] = {
298 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x2, 0xa0,
299 };
300
Simon Glass8ceca1d2018-11-18 14:22:27 -0700301 return tpm_sendrecv_command(dev, command, NULL, NULL);
Simon Glassbccabbe2018-10-01 12:22:29 -0600302}
303
Simon Glass8ceca1d2018-11-18 14:22:27 -0700304u32 tpm_read_pubek(struct udevice *dev, void *data, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000305{
Miquel Raynald790f552018-05-15 11:56:59 +0200306 const u8 command[30] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000307 0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c,
308 };
309 const size_t response_size_offset = 2;
310 const size_t data_offset = 10;
311 const size_t header_and_checksum_size = TPM_RESPONSE_HEADER_LENGTH + 20;
Miquel Raynald790f552018-05-15 11:56:59 +0200312 u8 response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000313 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200314 u32 data_size;
315 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000316
Simon Glass8ceca1d2018-11-18 14:22:27 -0700317 err = tpm_sendrecv_command(dev, command, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000318 if (err)
319 return err;
320 if (unpack_byte_string(response, response_length, "d",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200321 response_size_offset, &data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000322 return TPM_LIB_ERROR;
323 if (data_size < header_and_checksum_size)
324 return TPM_LIB_ERROR;
325 data_size -= header_and_checksum_size;
326 if (data_size > count)
327 return TPM_LIB_ERROR;
328 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200329 data_offset, data, data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000330 return TPM_LIB_ERROR;
331
332 return 0;
333}
334
Simon Glass8ceca1d2018-11-18 14:22:27 -0700335u32 tpm_force_clear(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000336{
Miquel Raynald790f552018-05-15 11:56:59 +0200337 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000338 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
339 };
340
Simon Glass8ceca1d2018-11-18 14:22:27 -0700341 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000342}
343
Simon Glass8ceca1d2018-11-18 14:22:27 -0700344u32 tpm_physical_enable(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000345{
Miquel Raynald790f552018-05-15 11:56:59 +0200346 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000347 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
348 };
349
Simon Glass8ceca1d2018-11-18 14:22:27 -0700350 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000351}
352
Simon Glass8ceca1d2018-11-18 14:22:27 -0700353u32 tpm_physical_disable(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000354{
Miquel Raynald790f552018-05-15 11:56:59 +0200355 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000356 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
357 };
358
Simon Glass8ceca1d2018-11-18 14:22:27 -0700359 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000360}
361
Simon Glass8ceca1d2018-11-18 14:22:27 -0700362u32 tpm_physical_set_deactivated(struct udevice *dev, u8 state)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000363{
Miquel Raynald790f552018-05-15 11:56:59 +0200364 const u8 command[11] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000365 0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72,
366 };
367 const size_t state_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200368 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000369
370 if (pack_byte_string(buf, sizeof(buf), "sb",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200371 0, command, sizeof(command),
372 state_offset, state))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000373 return TPM_LIB_ERROR;
374
Simon Glass8ceca1d2018-11-18 14:22:27 -0700375 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000376}
377
Simon Glass8ceca1d2018-11-18 14:22:27 -0700378u32 tpm_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap,
379 void *cap, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000380{
Miquel Raynald790f552018-05-15 11:56:59 +0200381 const u8 command[22] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000382 0x0, 0xc1, /* TPM_TAG */
383 0x0, 0x0, 0x0, 0x16, /* parameter size */
384 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
385 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */
386 0x0, 0x0, 0x0, 0x4, /* subcap size */
387 0x0, 0x0, 0x0, 0x0, /* subcap value */
388 };
389 const size_t cap_area_offset = 10;
390 const size_t sub_cap_offset = 18;
391 const size_t cap_offset = 14;
392 const size_t cap_size_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200393 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000394 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200395 u32 cap_size;
396 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000397
398 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200399 0, command, sizeof(command),
400 cap_area_offset, cap_area,
401 sub_cap_offset, sub_cap))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000402 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700403 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000404 if (err)
405 return err;
406 if (unpack_byte_string(response, response_length, "d",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200407 cap_size_offset, &cap_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000408 return TPM_LIB_ERROR;
409 if (cap_size > response_length || cap_size > count)
410 return TPM_LIB_ERROR;
411 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200412 cap_offset, cap, cap_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000413 return TPM_LIB_ERROR;
414
415 return 0;
416}
Reinhard Pfau4fece432013-06-26 15:55:13 +0200417
Simon Glass8ceca1d2018-11-18 14:22:27 -0700418u32 tpm_get_permanent_flags(struct udevice *dev,
419 struct tpm_permanent_flags *pflags)
Simon Glassff9f04a2015-08-22 18:31:41 -0600420{
Miquel Raynald790f552018-05-15 11:56:59 +0200421 const u8 command[22] = {
Simon Glassff9f04a2015-08-22 18:31:41 -0600422 0x0, 0xc1, /* TPM_TAG */
423 0x0, 0x0, 0x0, 0x16, /* parameter size */
424 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
425 0x0, 0x0, 0x0, 0x4, /* TPM_CAP_FLAG_PERM */
426 0x0, 0x0, 0x0, 0x4, /* subcap size */
427 0x0, 0x0, 0x1, 0x8, /* subcap value */
428 };
André Draszik1361fbc2017-10-03 16:55:51 +0100429 const size_t data_size_offset = TPM_HEADER_SIZE;
Miquel Raynald790f552018-05-15 11:56:59 +0200430 const size_t data_offset = TPM_HEADER_SIZE + sizeof(u32);
431 u8 response[COMMAND_BUFFER_SIZE];
Simon Glassff9f04a2015-08-22 18:31:41 -0600432 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200433 u32 err;
434 u32 data_size;
Simon Glassff9f04a2015-08-22 18:31:41 -0600435
Simon Glass8ceca1d2018-11-18 14:22:27 -0700436 err = tpm_sendrecv_command(dev, command, response, &response_length);
Simon Glassff9f04a2015-08-22 18:31:41 -0600437 if (err)
438 return err;
André Draszik1361fbc2017-10-03 16:55:51 +0100439 if (unpack_byte_string(response, response_length, "d",
Simon Glassbccabbe2018-10-01 12:22:29 -0600440 data_size_offset, &data_size)) {
441 log_err("Cannot unpack data size\n");
André Draszik1361fbc2017-10-03 16:55:51 +0100442 return TPM_LIB_ERROR;
Simon Glassbccabbe2018-10-01 12:22:29 -0600443 }
444 if (data_size < sizeof(*pflags)) {
445 log_err("Data size too small\n");
André Draszik1361fbc2017-10-03 16:55:51 +0100446 return TPM_LIB_ERROR;
Simon Glassbccabbe2018-10-01 12:22:29 -0600447 }
André Draszik1361fbc2017-10-03 16:55:51 +0100448 if (unpack_byte_string(response, response_length, "s",
Simon Glassbccabbe2018-10-01 12:22:29 -0600449 data_offset, pflags, sizeof(*pflags))) {
450 log_err("Cannot unpack pflags\n");
André Draszik1361fbc2017-10-03 16:55:51 +0100451 return TPM_LIB_ERROR;
Simon Glassbccabbe2018-10-01 12:22:29 -0600452 }
Simon Glassff9f04a2015-08-22 18:31:41 -0600453
454 return 0;
455}
456
Simon Glass8ceca1d2018-11-18 14:22:27 -0700457u32 tpm_get_permissions(struct udevice *dev, u32 index, u32 *perm)
Simon Glassff9f04a2015-08-22 18:31:41 -0600458{
Miquel Raynald790f552018-05-15 11:56:59 +0200459 const u8 command[22] = {
Simon Glassff9f04a2015-08-22 18:31:41 -0600460 0x0, 0xc1, /* TPM_TAG */
461 0x0, 0x0, 0x0, 0x16, /* parameter size */
462 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
463 0x0, 0x0, 0x0, 0x11,
464 0x0, 0x0, 0x0, 0x4,
465 };
466 const size_t index_offset = 18;
467 const size_t perm_offset = 60;
Miquel Raynald790f552018-05-15 11:56:59 +0200468 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Simon Glassff9f04a2015-08-22 18:31:41 -0600469 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200470 u32 err;
Simon Glassff9f04a2015-08-22 18:31:41 -0600471
472 if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command),
473 index_offset, index))
474 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700475 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Simon Glassff9f04a2015-08-22 18:31:41 -0600476 if (err)
477 return err;
478 if (unpack_byte_string(response, response_length, "d",
479 perm_offset, perm))
480 return TPM_LIB_ERROR;
481
482 return 0;
483}
484
Mario Six4eceb6c2017-01-11 16:00:50 +0100485#ifdef CONFIG_TPM_FLUSH_RESOURCES
Simon Glass8ceca1d2018-11-18 14:22:27 -0700486u32 tpm_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type)
Mario Six4eceb6c2017-01-11 16:00:50 +0100487{
Miquel Raynald790f552018-05-15 11:56:59 +0200488 const u8 command[18] = {
Mario Six4eceb6c2017-01-11 16:00:50 +0100489 0x00, 0xc1, /* TPM_TAG */
490 0x00, 0x00, 0x00, 0x12, /* parameter size */
491 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
492 0x00, 0x00, 0x00, 0x00, /* key handle */
493 0x00, 0x00, 0x00, 0x00, /* resource type */
494 };
495 const size_t key_handle_offset = 10;
496 const size_t resource_type_offset = 14;
Miquel Raynald790f552018-05-15 11:56:59 +0200497 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Mario Six4eceb6c2017-01-11 16:00:50 +0100498 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200499 u32 err;
Mario Six4eceb6c2017-01-11 16:00:50 +0100500
501 if (pack_byte_string(buf, sizeof(buf), "sdd",
502 0, command, sizeof(command),
503 key_handle_offset, key_handle,
504 resource_type_offset, resource_type))
505 return TPM_LIB_ERROR;
506
Simon Glass8ceca1d2018-11-18 14:22:27 -0700507 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Mario Six4eceb6c2017-01-11 16:00:50 +0100508 if (err)
509 return err;
510 return 0;
511}
512#endif /* CONFIG_TPM_FLUSH_RESOURCES */
513
Reinhard Pfau4fece432013-06-26 15:55:13 +0200514#ifdef CONFIG_TPM_AUTH_SESSIONS
515
516/**
517 * Fill an authentication block in a request.
518 * This func can create the first as well as the second auth block (for
519 * double authorized commands).
520 *
521 * @param request pointer to the request (w/ uninitialised auth data)
522 * @param request_len0 length of the request without auth data
523 * @param handles_len length of the handles area in request
524 * @param auth_session pointer to the (valid) auth session to be used
525 * @param request_auth pointer to the auth block of the request to be filled
526 * @param auth authentication data (HMAC key)
527 */
Miquel Raynald790f552018-05-15 11:56:59 +0200528static u32 create_request_auth(const void *request, size_t request_len0,
529 size_t handles_len,
530 struct session_data *auth_session,
531 void *request_auth, const void *auth)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200532{
Miquel Raynald790f552018-05-15 11:56:59 +0200533 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200534 sha1_context hash_ctx;
535 const size_t command_code_offset = 6;
536 const size_t auth_nonce_odd_offset = 4;
537 const size_t auth_continue_offset = 24;
538 const size_t auth_auth_offset = 25;
539
540 if (!auth_session || !auth_session->valid)
541 return TPM_LIB_ERROR;
542
543 sha1_starts(&hash_ctx);
544 sha1_update(&hash_ctx, request + command_code_offset, 4);
545 if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
546 sha1_update(&hash_ctx,
547 request + TPM_REQUEST_HEADER_LENGTH + handles_len,
548 request_len0 - TPM_REQUEST_HEADER_LENGTH
549 - handles_len);
550 sha1_finish(&hash_ctx, hmac_data);
551
552 sha1_starts(&hash_ctx);
553 sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
554 sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
555 sha1_finish(&hash_ctx, auth_session->nonce_odd);
556
557 if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
558 0, auth_session->handle,
559 auth_nonce_odd_offset, auth_session->nonce_odd,
560 DIGEST_LENGTH,
561 auth_continue_offset, 1))
562 return TPM_LIB_ERROR;
563 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
564 DIGEST_LENGTH,
565 auth_session->nonce_even,
566 DIGEST_LENGTH,
567 2 * DIGEST_LENGTH,
568 request_auth + auth_nonce_odd_offset,
569 DIGEST_LENGTH + 1))
570 return TPM_LIB_ERROR;
571 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
572 request_auth + auth_auth_offset);
573
574 return TPM_SUCCESS;
575}
576
577/**
578 * Verify an authentication block in a response.
579 * Since this func updates the nonce_even in the session data it has to be
580 * called when receiving a succesfull AUTH response.
581 * This func can verify the first as well as the second auth block (for
582 * double authorized commands).
583 *
584 * @param command_code command code of the request
585 * @param response pointer to the request (w/ uninitialised auth data)
586 * @param handles_len length of the handles area in response
587 * @param auth_session pointer to the (valid) auth session to be used
588 * @param response_auth pointer to the auth block of the response to be verified
589 * @param auth authentication data (HMAC key)
590 */
Miquel Raynald790f552018-05-15 11:56:59 +0200591static u32 verify_response_auth(u32 command_code, const void *response,
592 size_t response_len0, size_t handles_len,
593 struct session_data *auth_session,
594 const void *response_auth, const void *auth)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200595{
Miquel Raynald790f552018-05-15 11:56:59 +0200596 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
597 u8 computed_auth[DIGEST_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200598 sha1_context hash_ctx;
599 const size_t return_code_offset = 6;
600 const size_t auth_continue_offset = 20;
601 const size_t auth_auth_offset = 21;
Miquel Raynald790f552018-05-15 11:56:59 +0200602 u8 auth_continue;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200603
604 if (!auth_session || !auth_session->valid)
605 return TPM_AUTHFAIL;
606 if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
607 0, command_code))
608 return TPM_LIB_ERROR;
609 if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
610 return TPM_LIB_ERROR;
611
612 sha1_starts(&hash_ctx);
613 sha1_update(&hash_ctx, response + return_code_offset, 4);
614 sha1_update(&hash_ctx, hmac_data, 4);
615 if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
616 sha1_update(&hash_ctx,
617 response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
618 response_len0 - TPM_RESPONSE_HEADER_LENGTH
619 - handles_len);
620 sha1_finish(&hash_ctx, hmac_data);
621
622 memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
Miquel Raynald790f552018-05-15 11:56:59 +0200623 auth_continue = ((u8 *)response_auth)[auth_continue_offset];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200624 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
625 DIGEST_LENGTH,
626 response_auth,
627 DIGEST_LENGTH,
628 2 * DIGEST_LENGTH,
629 auth_session->nonce_odd,
630 DIGEST_LENGTH,
631 3 * DIGEST_LENGTH,
632 auth_continue))
633 return TPM_LIB_ERROR;
634
635 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
636 computed_auth);
637
638 if (memcmp(computed_auth, response_auth + auth_auth_offset,
639 DIGEST_LENGTH))
640 return TPM_AUTHFAIL;
641
642 return TPM_SUCCESS;
643}
644
Simon Glass8ceca1d2018-11-18 14:22:27 -0700645u32 tpm_terminate_auth_session(struct udevice *dev, u32 auth_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200646{
Miquel Raynald790f552018-05-15 11:56:59 +0200647 const u8 command[18] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200648 0x00, 0xc1, /* TPM_TAG */
649 0x00, 0x00, 0x00, 0x00, /* parameter size */
650 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
651 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
Miquel Raynala59aa342018-05-15 11:57:02 +0200652 0x00, 0x00, 0x00, 0x02, /* TPM_RESOURCE_TYPE */
Reinhard Pfau4fece432013-06-26 15:55:13 +0200653 };
654 const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200655 u8 request[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200656
657 if (pack_byte_string(request, sizeof(request), "sd",
658 0, command, sizeof(command),
659 req_handle_offset, auth_handle))
660 return TPM_LIB_ERROR;
661 if (oiap_session.valid && oiap_session.handle == auth_handle)
662 oiap_session.valid = 0;
663
Simon Glass8ceca1d2018-11-18 14:22:27 -0700664 return tpm_sendrecv_command(dev, request, NULL, NULL);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200665}
666
Simon Glass8ceca1d2018-11-18 14:22:27 -0700667u32 tpm_end_oiap(struct udevice *dev)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200668{
Miquel Raynald790f552018-05-15 11:56:59 +0200669 u32 err = TPM_SUCCESS;
Miquel Raynal82b05662018-05-15 11:57:03 +0200670
Reinhard Pfau4fece432013-06-26 15:55:13 +0200671 if (oiap_session.valid)
Simon Glass8ceca1d2018-11-18 14:22:27 -0700672 err = tpm_terminate_auth_session(dev, oiap_session.handle);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200673 return err;
674}
675
Simon Glass8ceca1d2018-11-18 14:22:27 -0700676u32 tpm_oiap(struct udevice *dev, u32 *auth_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200677{
Miquel Raynald790f552018-05-15 11:56:59 +0200678 const u8 command[10] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200679 0x00, 0xc1, /* TPM_TAG */
680 0x00, 0x00, 0x00, 0x0a, /* parameter size */
681 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
682 };
683 const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
684 const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
Miquel Raynald790f552018-05-15 11:56:59 +0200685 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200686 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200687 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200688
689 if (oiap_session.valid)
Simon Glass8ceca1d2018-11-18 14:22:27 -0700690 tpm_terminate_auth_session(dev, oiap_session.handle);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200691
Simon Glass8ceca1d2018-11-18 14:22:27 -0700692 err = tpm_sendrecv_command(dev, command, response, &response_length);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200693 if (err)
694 return err;
695 if (unpack_byte_string(response, response_length, "ds",
696 res_auth_handle_offset, &oiap_session.handle,
697 res_nonce_even_offset, &oiap_session.nonce_even,
Miquel Raynald790f552018-05-15 11:56:59 +0200698 (u32)DIGEST_LENGTH))
Reinhard Pfau4fece432013-06-26 15:55:13 +0200699 return TPM_LIB_ERROR;
700 oiap_session.valid = 1;
701 if (auth_handle)
702 *auth_handle = oiap_session.handle;
703 return 0;
704}
705
Simon Glass8ceca1d2018-11-18 14:22:27 -0700706u32 tpm_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key,
707 size_t key_length, const void *parent_key_usage_auth,
708 u32 *key_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200709{
Miquel Raynald790f552018-05-15 11:56:59 +0200710 const u8 command[14] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200711 0x00, 0xc2, /* TPM_TAG */
712 0x00, 0x00, 0x00, 0x00, /* parameter size */
713 0x00, 0x00, 0x00, 0x41, /* TPM_COMMAND_CODE */
714 0x00, 0x00, 0x00, 0x00, /* parent handle */
715 };
716 const size_t req_size_offset = 2;
717 const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
718 const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
719 const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200720 u8 request[sizeof(command) + TPM_KEY12_MAX_LENGTH +
721 TPM_REQUEST_AUTH_LENGTH];
722 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200723 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200724 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200725
726 if (!oiap_session.valid) {
Simon Glass8ceca1d2018-11-18 14:22:27 -0700727 err = tpm_oiap(dev, NULL);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200728 if (err)
729 return err;
730 }
731 if (pack_byte_string(request, sizeof(request), "sdds",
732 0, command, sizeof(command),
733 req_size_offset,
734 sizeof(command) + key_length
735 + TPM_REQUEST_AUTH_LENGTH,
736 req_parent_handle_offset, parent_handle,
737 req_key_offset, key, key_length
738 ))
739 return TPM_LIB_ERROR;
740
741 err = create_request_auth(request, sizeof(command) + key_length, 4,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200742 &oiap_session,
743 request + sizeof(command) + key_length,
744 parent_key_usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200745 if (err)
746 return err;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700747 err = tpm_sendrecv_command(dev, request, response, &response_length);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200748 if (err) {
749 if (err == TPM_AUTHFAIL)
750 oiap_session.valid = 0;
751 return err;
752 }
753
754 err = verify_response_auth(0x00000041, response,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200755 response_length - TPM_RESPONSE_AUTH_LENGTH,
756 4, &oiap_session,
757 response + response_length -
758 TPM_RESPONSE_AUTH_LENGTH,
759 parent_key_usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200760 if (err)
761 return err;
762
763 if (key_handle) {
764 if (unpack_byte_string(response, response_length, "d",
765 res_handle_offset, key_handle))
766 return TPM_LIB_ERROR;
767 }
768
769 return 0;
770}
771
Simon Glass8ceca1d2018-11-18 14:22:27 -0700772u32 tpm_get_pub_key_oiap(struct udevice *dev, u32 key_handle,
773 const void *usage_auth, void *pubkey,
Miquel Raynald790f552018-05-15 11:56:59 +0200774 size_t *pubkey_len)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200775{
Miquel Raynald790f552018-05-15 11:56:59 +0200776 const u8 command[14] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200777 0x00, 0xc2, /* TPM_TAG */
778 0x00, 0x00, 0x00, 0x00, /* parameter size */
779 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
780 0x00, 0x00, 0x00, 0x00, /* key handle */
781 };
782 const size_t req_size_offset = 2;
783 const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
784 const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200785 u8 request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
786 u8 response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH +
787 TPM_RESPONSE_AUTH_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200788 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200789 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200790
791 if (!oiap_session.valid) {
Simon Glass8ceca1d2018-11-18 14:22:27 -0700792 err = tpm_oiap(dev, NULL);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200793 if (err)
794 return err;
795 }
796 if (pack_byte_string(request, sizeof(request), "sdd",
797 0, command, sizeof(command),
798 req_size_offset,
Miquel Raynald790f552018-05-15 11:56:59 +0200799 (u32)(sizeof(command)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200800 + TPM_REQUEST_AUTH_LENGTH),
801 req_key_handle_offset, key_handle
802 ))
803 return TPM_LIB_ERROR;
804 err = create_request_auth(request, sizeof(command), 4, &oiap_session,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200805 request + sizeof(command), usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200806 if (err)
807 return err;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700808 err = tpm_sendrecv_command(dev, request, response, &response_length);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200809 if (err) {
810 if (err == TPM_AUTHFAIL)
811 oiap_session.valid = 0;
812 return err;
813 }
814 err = verify_response_auth(0x00000021, response,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200815 response_length - TPM_RESPONSE_AUTH_LENGTH,
816 0, &oiap_session,
817 response + response_length -
818 TPM_RESPONSE_AUTH_LENGTH,
819 usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200820 if (err)
821 return err;
822
823 if (pubkey) {
824 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
Miquel Raynal886ccc02018-05-15 11:57:00 +0200825 - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200826 return TPM_LIB_ERROR;
827 *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
828 - TPM_RESPONSE_AUTH_LENGTH;
829 memcpy(pubkey, response + res_pubkey_offset,
830 response_length - TPM_RESPONSE_HEADER_LENGTH
831 - TPM_RESPONSE_AUTH_LENGTH);
832 }
833
834 return 0;
835}
836
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100837#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
Simon Glass8ceca1d2018-11-18 14:22:27 -0700838u32 tpm_find_key_sha1(struct udevice *dev, const u8 auth[20],
839 const u8 pubkey_digest[20], u32 *handle)
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100840{
Miquel Raynald790f552018-05-15 11:56:59 +0200841 u16 key_count;
842 u32 key_handles[10];
843 u8 buf[288];
844 u8 *ptr;
845 u32 err;
846 u8 digest[20];
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100847 size_t buf_len;
848 unsigned int i;
849
850 /* fetch list of already loaded keys in the TPM */
Simon Glass8ceca1d2018-11-18 14:22:27 -0700851 err = tpm_get_capability(dev, TPM_CAP_HANDLE, TPM_RT_KEY, buf,
852 sizeof(buf));
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100853 if (err)
854 return -1;
855 key_count = get_unaligned_be16(buf);
856 ptr = buf + 2;
857 for (i = 0; i < key_count; ++i, ptr += 4)
858 key_handles[i] = get_unaligned_be32(ptr);
859
860 /* now search a(/ the) key which we can access with the given auth */
861 for (i = 0; i < key_count; ++i) {
862 buf_len = sizeof(buf);
863 err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len);
864 if (err && err != TPM_AUTHFAIL)
865 return -1;
866 if (err)
867 continue;
868 sha1_csum(buf, buf_len, digest);
869 if (!memcmp(digest, pubkey_digest, 20)) {
870 *handle = key_handles[i];
871 return 0;
872 }
873 }
874 return 1;
875}
876#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
877
Reinhard Pfau4fece432013-06-26 15:55:13 +0200878#endif /* CONFIG_TPM_AUTH_SESSIONS */
André Draszik2c6e5ff2017-10-03 16:55:52 +0100879
Simon Glass8ceca1d2018-11-18 14:22:27 -0700880u32 tpm_get_random(struct udevice *dev, void *data, u32 count)
André Draszik2c6e5ff2017-10-03 16:55:52 +0100881{
Miquel Raynald790f552018-05-15 11:56:59 +0200882 const u8 command[14] = {
André Draszik2c6e5ff2017-10-03 16:55:52 +0100883 0x0, 0xc1, /* TPM_TAG */
884 0x0, 0x0, 0x0, 0xe, /* parameter size */
885 0x0, 0x0, 0x0, 0x46, /* TPM_COMMAND_CODE */
886 };
887 const size_t length_offset = 10;
888 const size_t data_size_offset = 10;
889 const size_t data_offset = 14;
Miquel Raynald790f552018-05-15 11:56:59 +0200890 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
André Draszik2c6e5ff2017-10-03 16:55:52 +0100891 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200892 u32 data_size;
893 u8 *out = data;
André Draszik2c6e5ff2017-10-03 16:55:52 +0100894
895 while (count > 0) {
Miquel Raynald790f552018-05-15 11:56:59 +0200896 u32 this_bytes = min((size_t)count,
897 sizeof(response) - data_offset);
898 u32 err;
André Draszik2c6e5ff2017-10-03 16:55:52 +0100899
900 if (pack_byte_string(buf, sizeof(buf), "sd",
901 0, command, sizeof(command),
902 length_offset, this_bytes))
903 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700904 err = tpm_sendrecv_command(dev, buf, response,
905 &response_length);
André Draszik2c6e5ff2017-10-03 16:55:52 +0100906 if (err)
907 return err;
908 if (unpack_byte_string(response, response_length, "d",
909 data_size_offset, &data_size))
910 return TPM_LIB_ERROR;
911 if (data_size > count)
912 return TPM_LIB_ERROR;
913 if (unpack_byte_string(response, response_length, "s",
914 data_offset, out, data_size))
915 return TPM_LIB_ERROR;
916
917 count -= data_size;
918 out += data_size;
919 }
920
921 return 0;
922}