blob: b4498e6afc7ee6e38dd08617e6652e72f0c0e2b5 [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{
Heinrich Schuchardt060aefc2019-02-05 01:38:41 +0100214 return tpm_nv_write_value(dev, TPM_NV_INDEX_0, NULL, 0);
Simon Glassbccabbe2018-10-01 12:22:29 -0600215}
216
Simon Glass8ceca1d2018-11-18 14:22:27 -0700217u32 tpm_extend(struct udevice *dev, u32 index, const void *in_digest,
218 void *out_digest)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000219{
Miquel Raynald790f552018-05-15 11:56:59 +0200220 const u8 command[34] = {
Che-liang Chiouc18f9012013-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 Raynald790f552018-05-15 11:56:59 +0200226 u8 buf[COMMAND_BUFFER_SIZE];
227 u8 response[TPM_RESPONSE_HEADER_LENGTH + PCR_DIGEST_LENGTH];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000228 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200229 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000230
231 if (pack_byte_string(buf, sizeof(buf), "sds",
Miquel Raynal886ccc02018-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 Chiouc18f9012013-02-28 09:34:57 +0000236 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700237 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000238 if (err)
239 return err;
240
241 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200242 out_digest_offset, out_digest,
243 PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000244 return TPM_LIB_ERROR;
245
246 return 0;
247}
248
Simon Glass8ceca1d2018-11-18 14:22:27 -0700249u32 tpm_pcr_read(struct udevice *dev, u32 index, void *data, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000250{
Miquel Raynald790f552018-05-15 11:56:59 +0200251 const u8 command[14] = {
Che-liang Chiouc18f9012013-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 Raynald790f552018-05-15 11:56:59 +0200256 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000257 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200258 u32 err;
Che-liang Chiouc18f9012013-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 Raynal886ccc02018-05-15 11:57:00 +0200264 0, command, sizeof(command),
265 index_offset, index))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000266 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700267 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000268 if (err)
269 return err;
270 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200271 out_digest_offset, data, PCR_DIGEST_LENGTH))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000272 return TPM_LIB_ERROR;
273
274 return 0;
275}
276
Simon Glass8ceca1d2018-11-18 14:22:27 -0700277u32 tpm_tsc_physical_presence(struct udevice *dev, u16 presence)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000278{
Miquel Raynald790f552018-05-15 11:56:59 +0200279 const u8 command[12] = {
Che-liang Chiouc18f9012013-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 Raynald790f552018-05-15 11:56:59 +0200283 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000284
285 if (pack_byte_string(buf, sizeof(buf), "sw",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200286 0, command, sizeof(command),
287 presence_offset, presence))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000288 return TPM_LIB_ERROR;
289
Simon Glass8ceca1d2018-11-18 14:22:27 -0700290 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000291}
292
Simon Glass8ceca1d2018-11-18 14:22:27 -0700293u32 tpm_finalise_physical_presence(struct udevice *dev)
Simon Glassbccabbe2018-10-01 12:22:29 -0600294{
295 const u8 command[12] = {
296 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x2, 0xa0,
297 };
298
Simon Glass8ceca1d2018-11-18 14:22:27 -0700299 return tpm_sendrecv_command(dev, command, NULL, NULL);
Simon Glassbccabbe2018-10-01 12:22:29 -0600300}
301
Simon Glass8ceca1d2018-11-18 14:22:27 -0700302u32 tpm_read_pubek(struct udevice *dev, void *data, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000303{
Miquel Raynald790f552018-05-15 11:56:59 +0200304 const u8 command[30] = {
Che-liang Chiouc18f9012013-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 Raynald790f552018-05-15 11:56:59 +0200310 u8 response[COMMAND_BUFFER_SIZE + TPM_PUBEK_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000311 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200312 u32 data_size;
313 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000314
Simon Glass8ceca1d2018-11-18 14:22:27 -0700315 err = tpm_sendrecv_command(dev, command, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000316 if (err)
317 return err;
318 if (unpack_byte_string(response, response_length, "d",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200319 response_size_offset, &data_size))
Che-liang Chiouc18f9012013-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 Raynal886ccc02018-05-15 11:57:00 +0200327 data_offset, data, data_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000328 return TPM_LIB_ERROR;
329
330 return 0;
331}
332
Simon Glass8ceca1d2018-11-18 14:22:27 -0700333u32 tpm_force_clear(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000334{
Miquel Raynald790f552018-05-15 11:56:59 +0200335 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000336 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d,
337 };
338
Simon Glass8ceca1d2018-11-18 14:22:27 -0700339 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000340}
341
Simon Glass8ceca1d2018-11-18 14:22:27 -0700342u32 tpm_physical_enable(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000343{
Miquel Raynald790f552018-05-15 11:56:59 +0200344 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000345 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f,
346 };
347
Simon Glass8ceca1d2018-11-18 14:22:27 -0700348 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000349}
350
Simon Glass8ceca1d2018-11-18 14:22:27 -0700351u32 tpm_physical_disable(struct udevice *dev)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000352{
Miquel Raynald790f552018-05-15 11:56:59 +0200353 const u8 command[10] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000354 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70,
355 };
356
Simon Glass8ceca1d2018-11-18 14:22:27 -0700357 return tpm_sendrecv_command(dev, command, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000358}
359
Simon Glass8ceca1d2018-11-18 14:22:27 -0700360u32 tpm_physical_set_deactivated(struct udevice *dev, u8 state)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000361{
Miquel Raynald790f552018-05-15 11:56:59 +0200362 const u8 command[11] = {
Che-liang Chiouc18f9012013-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 Raynald790f552018-05-15 11:56:59 +0200366 u8 buf[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000367
368 if (pack_byte_string(buf, sizeof(buf), "sb",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200369 0, command, sizeof(command),
370 state_offset, state))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000371 return TPM_LIB_ERROR;
372
Simon Glass8ceca1d2018-11-18 14:22:27 -0700373 return tpm_sendrecv_command(dev, buf, NULL, NULL);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000374}
375
Simon Glass8ceca1d2018-11-18 14:22:27 -0700376u32 tpm_get_capability(struct udevice *dev, u32 cap_area, u32 sub_cap,
377 void *cap, size_t count)
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000378{
Miquel Raynald790f552018-05-15 11:56:59 +0200379 const u8 command[22] = {
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000380 0x0, 0xc1, /* TPM_TAG */
381 0x0, 0x0, 0x0, 0x16, /* parameter size */
382 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
383 0x0, 0x0, 0x0, 0x0, /* TPM_CAPABILITY_AREA */
384 0x0, 0x0, 0x0, 0x4, /* subcap size */
385 0x0, 0x0, 0x0, 0x0, /* subcap value */
386 };
387 const size_t cap_area_offset = 10;
388 const size_t sub_cap_offset = 18;
389 const size_t cap_offset = 14;
390 const size_t cap_size_offset = 10;
Miquel Raynald790f552018-05-15 11:56:59 +0200391 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000392 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200393 u32 cap_size;
394 u32 err;
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000395
396 if (pack_byte_string(buf, sizeof(buf), "sdd",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200397 0, command, sizeof(command),
398 cap_area_offset, cap_area,
399 sub_cap_offset, sub_cap))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000400 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700401 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000402 if (err)
403 return err;
404 if (unpack_byte_string(response, response_length, "d",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200405 cap_size_offset, &cap_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000406 return TPM_LIB_ERROR;
407 if (cap_size > response_length || cap_size > count)
408 return TPM_LIB_ERROR;
409 if (unpack_byte_string(response, response_length, "s",
Miquel Raynal886ccc02018-05-15 11:57:00 +0200410 cap_offset, cap, cap_size))
Che-liang Chiouc18f9012013-02-28 09:34:57 +0000411 return TPM_LIB_ERROR;
412
413 return 0;
414}
Reinhard Pfau4fece432013-06-26 15:55:13 +0200415
Simon Glass8ceca1d2018-11-18 14:22:27 -0700416u32 tpm_get_permanent_flags(struct udevice *dev,
417 struct tpm_permanent_flags *pflags)
Simon Glassff9f04a2015-08-22 18:31:41 -0600418{
Miquel Raynald790f552018-05-15 11:56:59 +0200419 const u8 command[22] = {
Simon Glassff9f04a2015-08-22 18:31:41 -0600420 0x0, 0xc1, /* TPM_TAG */
421 0x0, 0x0, 0x0, 0x16, /* parameter size */
422 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
423 0x0, 0x0, 0x0, 0x4, /* TPM_CAP_FLAG_PERM */
424 0x0, 0x0, 0x0, 0x4, /* subcap size */
425 0x0, 0x0, 0x1, 0x8, /* subcap value */
426 };
André Draszik1361fbc2017-10-03 16:55:51 +0100427 const size_t data_size_offset = TPM_HEADER_SIZE;
Miquel Raynald790f552018-05-15 11:56:59 +0200428 const size_t data_offset = TPM_HEADER_SIZE + sizeof(u32);
429 u8 response[COMMAND_BUFFER_SIZE];
Simon Glassff9f04a2015-08-22 18:31:41 -0600430 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200431 u32 err;
432 u32 data_size;
Simon Glassff9f04a2015-08-22 18:31:41 -0600433
Simon Glass8ceca1d2018-11-18 14:22:27 -0700434 err = tpm_sendrecv_command(dev, command, response, &response_length);
Simon Glassff9f04a2015-08-22 18:31:41 -0600435 if (err)
436 return err;
André Draszik1361fbc2017-10-03 16:55:51 +0100437 if (unpack_byte_string(response, response_length, "d",
Simon Glassbccabbe2018-10-01 12:22:29 -0600438 data_size_offset, &data_size)) {
439 log_err("Cannot unpack data size\n");
André Draszik1361fbc2017-10-03 16:55:51 +0100440 return TPM_LIB_ERROR;
Simon Glassbccabbe2018-10-01 12:22:29 -0600441 }
442 if (data_size < sizeof(*pflags)) {
443 log_err("Data size too small\n");
André Draszik1361fbc2017-10-03 16:55:51 +0100444 return TPM_LIB_ERROR;
Simon Glassbccabbe2018-10-01 12:22:29 -0600445 }
André Draszik1361fbc2017-10-03 16:55:51 +0100446 if (unpack_byte_string(response, response_length, "s",
Simon Glassbccabbe2018-10-01 12:22:29 -0600447 data_offset, pflags, sizeof(*pflags))) {
448 log_err("Cannot unpack pflags\n");
André Draszik1361fbc2017-10-03 16:55:51 +0100449 return TPM_LIB_ERROR;
Simon Glassbccabbe2018-10-01 12:22:29 -0600450 }
Simon Glassff9f04a2015-08-22 18:31:41 -0600451
452 return 0;
453}
454
Simon Glass8ceca1d2018-11-18 14:22:27 -0700455u32 tpm_get_permissions(struct udevice *dev, u32 index, u32 *perm)
Simon Glassff9f04a2015-08-22 18:31:41 -0600456{
Miquel Raynald790f552018-05-15 11:56:59 +0200457 const u8 command[22] = {
Simon Glassff9f04a2015-08-22 18:31:41 -0600458 0x0, 0xc1, /* TPM_TAG */
459 0x0, 0x0, 0x0, 0x16, /* parameter size */
460 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
461 0x0, 0x0, 0x0, 0x11,
462 0x0, 0x0, 0x0, 0x4,
463 };
464 const size_t index_offset = 18;
465 const size_t perm_offset = 60;
Miquel Raynald790f552018-05-15 11:56:59 +0200466 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Simon Glassff9f04a2015-08-22 18:31:41 -0600467 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200468 u32 err;
Simon Glassff9f04a2015-08-22 18:31:41 -0600469
470 if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command),
471 index_offset, index))
472 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700473 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Simon Glassff9f04a2015-08-22 18:31:41 -0600474 if (err)
475 return err;
476 if (unpack_byte_string(response, response_length, "d",
477 perm_offset, perm))
478 return TPM_LIB_ERROR;
479
480 return 0;
481}
482
Mario Six4eceb6c2017-01-11 16:00:50 +0100483#ifdef CONFIG_TPM_FLUSH_RESOURCES
Simon Glass8ceca1d2018-11-18 14:22:27 -0700484u32 tpm_flush_specific(struct udevice *dev, u32 key_handle, u32 resource_type)
Mario Six4eceb6c2017-01-11 16:00:50 +0100485{
Miquel Raynald790f552018-05-15 11:56:59 +0200486 const u8 command[18] = {
Mario Six4eceb6c2017-01-11 16:00:50 +0100487 0x00, 0xc1, /* TPM_TAG */
488 0x00, 0x00, 0x00, 0x12, /* parameter size */
489 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
490 0x00, 0x00, 0x00, 0x00, /* key handle */
491 0x00, 0x00, 0x00, 0x00, /* resource type */
492 };
493 const size_t key_handle_offset = 10;
494 const size_t resource_type_offset = 14;
Miquel Raynald790f552018-05-15 11:56:59 +0200495 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
Mario Six4eceb6c2017-01-11 16:00:50 +0100496 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200497 u32 err;
Mario Six4eceb6c2017-01-11 16:00:50 +0100498
499 if (pack_byte_string(buf, sizeof(buf), "sdd",
500 0, command, sizeof(command),
501 key_handle_offset, key_handle,
502 resource_type_offset, resource_type))
503 return TPM_LIB_ERROR;
504
Simon Glass8ceca1d2018-11-18 14:22:27 -0700505 err = tpm_sendrecv_command(dev, buf, response, &response_length);
Mario Six4eceb6c2017-01-11 16:00:50 +0100506 if (err)
507 return err;
508 return 0;
509}
510#endif /* CONFIG_TPM_FLUSH_RESOURCES */
511
Reinhard Pfau4fece432013-06-26 15:55:13 +0200512#ifdef CONFIG_TPM_AUTH_SESSIONS
513
514/**
515 * Fill an authentication block in a request.
516 * This func can create the first as well as the second auth block (for
517 * double authorized commands).
518 *
519 * @param request pointer to the request (w/ uninitialised auth data)
520 * @param request_len0 length of the request without auth data
521 * @param handles_len length of the handles area in request
522 * @param auth_session pointer to the (valid) auth session to be used
523 * @param request_auth pointer to the auth block of the request to be filled
524 * @param auth authentication data (HMAC key)
525 */
Miquel Raynald790f552018-05-15 11:56:59 +0200526static u32 create_request_auth(const void *request, size_t request_len0,
527 size_t handles_len,
528 struct session_data *auth_session,
529 void *request_auth, const void *auth)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200530{
Miquel Raynald790f552018-05-15 11:56:59 +0200531 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200532 sha1_context hash_ctx;
533 const size_t command_code_offset = 6;
534 const size_t auth_nonce_odd_offset = 4;
535 const size_t auth_continue_offset = 24;
536 const size_t auth_auth_offset = 25;
537
538 if (!auth_session || !auth_session->valid)
539 return TPM_LIB_ERROR;
540
541 sha1_starts(&hash_ctx);
542 sha1_update(&hash_ctx, request + command_code_offset, 4);
543 if (request_len0 > TPM_REQUEST_HEADER_LENGTH + handles_len)
544 sha1_update(&hash_ctx,
545 request + TPM_REQUEST_HEADER_LENGTH + handles_len,
546 request_len0 - TPM_REQUEST_HEADER_LENGTH
547 - handles_len);
548 sha1_finish(&hash_ctx, hmac_data);
549
550 sha1_starts(&hash_ctx);
551 sha1_update(&hash_ctx, auth_session->nonce_odd, DIGEST_LENGTH);
552 sha1_update(&hash_ctx, hmac_data, sizeof(hmac_data));
553 sha1_finish(&hash_ctx, auth_session->nonce_odd);
554
555 if (pack_byte_string(request_auth, TPM_REQUEST_AUTH_LENGTH, "dsb",
556 0, auth_session->handle,
557 auth_nonce_odd_offset, auth_session->nonce_odd,
558 DIGEST_LENGTH,
559 auth_continue_offset, 1))
560 return TPM_LIB_ERROR;
561 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ss",
562 DIGEST_LENGTH,
563 auth_session->nonce_even,
564 DIGEST_LENGTH,
565 2 * DIGEST_LENGTH,
566 request_auth + auth_nonce_odd_offset,
567 DIGEST_LENGTH + 1))
568 return TPM_LIB_ERROR;
569 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
570 request_auth + auth_auth_offset);
571
572 return TPM_SUCCESS;
573}
574
575/**
576 * Verify an authentication block in a response.
577 * Since this func updates the nonce_even in the session data it has to be
578 * called when receiving a succesfull AUTH response.
579 * This func can verify the first as well as the second auth block (for
580 * double authorized commands).
581 *
582 * @param command_code command code of the request
583 * @param response pointer to the request (w/ uninitialised auth data)
584 * @param handles_len length of the handles area in response
585 * @param auth_session pointer to the (valid) auth session to be used
586 * @param response_auth pointer to the auth block of the response to be verified
587 * @param auth authentication data (HMAC key)
588 */
Miquel Raynald790f552018-05-15 11:56:59 +0200589static u32 verify_response_auth(u32 command_code, const void *response,
590 size_t response_len0, size_t handles_len,
591 struct session_data *auth_session,
592 const void *response_auth, const void *auth)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200593{
Miquel Raynald790f552018-05-15 11:56:59 +0200594 u8 hmac_data[DIGEST_LENGTH * 3 + 1];
595 u8 computed_auth[DIGEST_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200596 sha1_context hash_ctx;
597 const size_t return_code_offset = 6;
598 const size_t auth_continue_offset = 20;
599 const size_t auth_auth_offset = 21;
Miquel Raynald790f552018-05-15 11:56:59 +0200600 u8 auth_continue;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200601
602 if (!auth_session || !auth_session->valid)
603 return TPM_AUTHFAIL;
604 if (pack_byte_string(hmac_data, sizeof(hmac_data), "d",
605 0, command_code))
606 return TPM_LIB_ERROR;
607 if (response_len0 < TPM_RESPONSE_HEADER_LENGTH)
608 return TPM_LIB_ERROR;
609
610 sha1_starts(&hash_ctx);
611 sha1_update(&hash_ctx, response + return_code_offset, 4);
612 sha1_update(&hash_ctx, hmac_data, 4);
613 if (response_len0 > TPM_RESPONSE_HEADER_LENGTH + handles_len)
614 sha1_update(&hash_ctx,
615 response + TPM_RESPONSE_HEADER_LENGTH + handles_len,
616 response_len0 - TPM_RESPONSE_HEADER_LENGTH
617 - handles_len);
618 sha1_finish(&hash_ctx, hmac_data);
619
620 memcpy(auth_session->nonce_even, response_auth, DIGEST_LENGTH);
Miquel Raynald790f552018-05-15 11:56:59 +0200621 auth_continue = ((u8 *)response_auth)[auth_continue_offset];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200622 if (pack_byte_string(hmac_data, sizeof(hmac_data), "ssb",
623 DIGEST_LENGTH,
624 response_auth,
625 DIGEST_LENGTH,
626 2 * DIGEST_LENGTH,
627 auth_session->nonce_odd,
628 DIGEST_LENGTH,
629 3 * DIGEST_LENGTH,
630 auth_continue))
631 return TPM_LIB_ERROR;
632
633 sha1_hmac(auth, DIGEST_LENGTH, hmac_data, sizeof(hmac_data),
634 computed_auth);
635
636 if (memcmp(computed_auth, response_auth + auth_auth_offset,
637 DIGEST_LENGTH))
638 return TPM_AUTHFAIL;
639
640 return TPM_SUCCESS;
641}
642
Simon Glass8ceca1d2018-11-18 14:22:27 -0700643u32 tpm_terminate_auth_session(struct udevice *dev, u32 auth_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200644{
Miquel Raynald790f552018-05-15 11:56:59 +0200645 const u8 command[18] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200646 0x00, 0xc1, /* TPM_TAG */
647 0x00, 0x00, 0x00, 0x00, /* parameter size */
648 0x00, 0x00, 0x00, 0xba, /* TPM_COMMAND_CODE */
649 0x00, 0x00, 0x00, 0x00, /* TPM_HANDLE */
Miquel Raynala59aa342018-05-15 11:57:02 +0200650 0x00, 0x00, 0x00, 0x02, /* TPM_RESOURCE_TYPE */
Reinhard Pfau4fece432013-06-26 15:55:13 +0200651 };
652 const size_t req_handle_offset = TPM_REQUEST_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200653 u8 request[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200654
655 if (pack_byte_string(request, sizeof(request), "sd",
656 0, command, sizeof(command),
657 req_handle_offset, auth_handle))
658 return TPM_LIB_ERROR;
659 if (oiap_session.valid && oiap_session.handle == auth_handle)
660 oiap_session.valid = 0;
661
Simon Glass8ceca1d2018-11-18 14:22:27 -0700662 return tpm_sendrecv_command(dev, request, NULL, NULL);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200663}
664
Simon Glass8ceca1d2018-11-18 14:22:27 -0700665u32 tpm_end_oiap(struct udevice *dev)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200666{
Miquel Raynald790f552018-05-15 11:56:59 +0200667 u32 err = TPM_SUCCESS;
Miquel Raynal82b05662018-05-15 11:57:03 +0200668
Reinhard Pfau4fece432013-06-26 15:55:13 +0200669 if (oiap_session.valid)
Simon Glass8ceca1d2018-11-18 14:22:27 -0700670 err = tpm_terminate_auth_session(dev, oiap_session.handle);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200671 return err;
672}
673
Simon Glass8ceca1d2018-11-18 14:22:27 -0700674u32 tpm_oiap(struct udevice *dev, u32 *auth_handle)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200675{
Miquel Raynald790f552018-05-15 11:56:59 +0200676 const u8 command[10] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200677 0x00, 0xc1, /* TPM_TAG */
678 0x00, 0x00, 0x00, 0x0a, /* parameter size */
679 0x00, 0x00, 0x00, 0x0a, /* TPM_COMMAND_CODE */
680 };
681 const size_t res_auth_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
682 const size_t res_nonce_even_offset = TPM_RESPONSE_HEADER_LENGTH + 4;
Miquel Raynald790f552018-05-15 11:56:59 +0200683 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200684 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200685 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200686
687 if (oiap_session.valid)
Simon Glass8ceca1d2018-11-18 14:22:27 -0700688 tpm_terminate_auth_session(dev, oiap_session.handle);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200689
Simon Glass8ceca1d2018-11-18 14:22:27 -0700690 err = tpm_sendrecv_command(dev, command, response, &response_length);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200691 if (err)
692 return err;
693 if (unpack_byte_string(response, response_length, "ds",
694 res_auth_handle_offset, &oiap_session.handle,
695 res_nonce_even_offset, &oiap_session.nonce_even,
Miquel Raynald790f552018-05-15 11:56:59 +0200696 (u32)DIGEST_LENGTH))
Reinhard Pfau4fece432013-06-26 15:55:13 +0200697 return TPM_LIB_ERROR;
698 oiap_session.valid = 1;
699 if (auth_handle)
700 *auth_handle = oiap_session.handle;
701 return 0;
702}
703
Simon Glass8ceca1d2018-11-18 14:22:27 -0700704u32 tpm_load_key2_oiap(struct udevice *dev, u32 parent_handle, const void *key,
705 size_t key_length, const void *parent_key_usage_auth,
706 u32 *key_handle)
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, 0x41, /* TPM_COMMAND_CODE */
712 0x00, 0x00, 0x00, 0x00, /* parent handle */
713 };
714 const size_t req_size_offset = 2;
715 const size_t req_parent_handle_offset = TPM_REQUEST_HEADER_LENGTH;
716 const size_t req_key_offset = TPM_REQUEST_HEADER_LENGTH + 4;
717 const size_t res_handle_offset = TPM_RESPONSE_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200718 u8 request[sizeof(command) + TPM_KEY12_MAX_LENGTH +
719 TPM_REQUEST_AUTH_LENGTH];
720 u8 response[COMMAND_BUFFER_SIZE];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200721 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200722 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200723
724 if (!oiap_session.valid) {
Simon Glass8ceca1d2018-11-18 14:22:27 -0700725 err = tpm_oiap(dev, NULL);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200726 if (err)
727 return err;
728 }
729 if (pack_byte_string(request, sizeof(request), "sdds",
730 0, command, sizeof(command),
731 req_size_offset,
732 sizeof(command) + key_length
733 + TPM_REQUEST_AUTH_LENGTH,
734 req_parent_handle_offset, parent_handle,
735 req_key_offset, key, key_length
736 ))
737 return TPM_LIB_ERROR;
738
739 err = create_request_auth(request, sizeof(command) + key_length, 4,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200740 &oiap_session,
741 request + sizeof(command) + key_length,
742 parent_key_usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200743 if (err)
744 return err;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700745 err = tpm_sendrecv_command(dev, request, response, &response_length);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200746 if (err) {
747 if (err == TPM_AUTHFAIL)
748 oiap_session.valid = 0;
749 return err;
750 }
751
752 err = verify_response_auth(0x00000041, response,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200753 response_length - TPM_RESPONSE_AUTH_LENGTH,
754 4, &oiap_session,
755 response + response_length -
756 TPM_RESPONSE_AUTH_LENGTH,
757 parent_key_usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200758 if (err)
759 return err;
760
761 if (key_handle) {
762 if (unpack_byte_string(response, response_length, "d",
763 res_handle_offset, key_handle))
764 return TPM_LIB_ERROR;
765 }
766
767 return 0;
768}
769
Simon Glass8ceca1d2018-11-18 14:22:27 -0700770u32 tpm_get_pub_key_oiap(struct udevice *dev, u32 key_handle,
771 const void *usage_auth, void *pubkey,
Miquel Raynald790f552018-05-15 11:56:59 +0200772 size_t *pubkey_len)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200773{
Miquel Raynald790f552018-05-15 11:56:59 +0200774 const u8 command[14] = {
Reinhard Pfau4fece432013-06-26 15:55:13 +0200775 0x00, 0xc2, /* TPM_TAG */
776 0x00, 0x00, 0x00, 0x00, /* parameter size */
777 0x00, 0x00, 0x00, 0x21, /* TPM_COMMAND_CODE */
778 0x00, 0x00, 0x00, 0x00, /* key handle */
779 };
780 const size_t req_size_offset = 2;
781 const size_t req_key_handle_offset = TPM_REQUEST_HEADER_LENGTH;
782 const size_t res_pubkey_offset = TPM_RESPONSE_HEADER_LENGTH;
Miquel Raynald790f552018-05-15 11:56:59 +0200783 u8 request[sizeof(command) + TPM_REQUEST_AUTH_LENGTH];
784 u8 response[TPM_RESPONSE_HEADER_LENGTH + TPM_PUBKEY_MAX_LENGTH +
785 TPM_RESPONSE_AUTH_LENGTH];
Reinhard Pfau4fece432013-06-26 15:55:13 +0200786 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200787 u32 err;
Reinhard Pfau4fece432013-06-26 15:55:13 +0200788
789 if (!oiap_session.valid) {
Simon Glass8ceca1d2018-11-18 14:22:27 -0700790 err = tpm_oiap(dev, NULL);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200791 if (err)
792 return err;
793 }
794 if (pack_byte_string(request, sizeof(request), "sdd",
795 0, command, sizeof(command),
796 req_size_offset,
Miquel Raynald790f552018-05-15 11:56:59 +0200797 (u32)(sizeof(command)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200798 + TPM_REQUEST_AUTH_LENGTH),
799 req_key_handle_offset, key_handle
800 ))
801 return TPM_LIB_ERROR;
802 err = create_request_auth(request, sizeof(command), 4, &oiap_session,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200803 request + sizeof(command), usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200804 if (err)
805 return err;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700806 err = tpm_sendrecv_command(dev, request, response, &response_length);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200807 if (err) {
808 if (err == TPM_AUTHFAIL)
809 oiap_session.valid = 0;
810 return err;
811 }
812 err = verify_response_auth(0x00000021, response,
Miquel Raynal886ccc02018-05-15 11:57:00 +0200813 response_length - TPM_RESPONSE_AUTH_LENGTH,
814 0, &oiap_session,
815 response + response_length -
816 TPM_RESPONSE_AUTH_LENGTH,
817 usage_auth);
Reinhard Pfau4fece432013-06-26 15:55:13 +0200818 if (err)
819 return err;
820
821 if (pubkey) {
822 if ((response_length - TPM_RESPONSE_HEADER_LENGTH
Miquel Raynal886ccc02018-05-15 11:57:00 +0200823 - TPM_RESPONSE_AUTH_LENGTH) > *pubkey_len)
Reinhard Pfau4fece432013-06-26 15:55:13 +0200824 return TPM_LIB_ERROR;
825 *pubkey_len = response_length - TPM_RESPONSE_HEADER_LENGTH
826 - TPM_RESPONSE_AUTH_LENGTH;
827 memcpy(pubkey, response + res_pubkey_offset,
828 response_length - TPM_RESPONSE_HEADER_LENGTH
829 - TPM_RESPONSE_AUTH_LENGTH);
830 }
831
832 return 0;
833}
834
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100835#ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1
Simon Glass8ceca1d2018-11-18 14:22:27 -0700836u32 tpm_find_key_sha1(struct udevice *dev, const u8 auth[20],
837 const u8 pubkey_digest[20], u32 *handle)
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100838{
Miquel Raynald790f552018-05-15 11:56:59 +0200839 u16 key_count;
840 u32 key_handles[10];
841 u8 buf[288];
842 u8 *ptr;
843 u32 err;
844 u8 digest[20];
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100845 size_t buf_len;
846 unsigned int i;
847
848 /* fetch list of already loaded keys in the TPM */
Simon Glass8ceca1d2018-11-18 14:22:27 -0700849 err = tpm_get_capability(dev, TPM_CAP_HANDLE, TPM_RT_KEY, buf,
850 sizeof(buf));
mario.six@gdsys.cca5a7ea22017-03-20 10:28:28 +0100851 if (err)
852 return -1;
853 key_count = get_unaligned_be16(buf);
854 ptr = buf + 2;
855 for (i = 0; i < key_count; ++i, ptr += 4)
856 key_handles[i] = get_unaligned_be32(ptr);
857
858 /* now search a(/ the) key which we can access with the given auth */
859 for (i = 0; i < key_count; ++i) {
860 buf_len = sizeof(buf);
861 err = tpm_get_pub_key_oiap(key_handles[i], auth, buf, &buf_len);
862 if (err && err != TPM_AUTHFAIL)
863 return -1;
864 if (err)
865 continue;
866 sha1_csum(buf, buf_len, digest);
867 if (!memcmp(digest, pubkey_digest, 20)) {
868 *handle = key_handles[i];
869 return 0;
870 }
871 }
872 return 1;
873}
874#endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */
875
Reinhard Pfau4fece432013-06-26 15:55:13 +0200876#endif /* CONFIG_TPM_AUTH_SESSIONS */
André Draszik2c6e5ff2017-10-03 16:55:52 +0100877
Simon Glass8ceca1d2018-11-18 14:22:27 -0700878u32 tpm_get_random(struct udevice *dev, void *data, u32 count)
André Draszik2c6e5ff2017-10-03 16:55:52 +0100879{
Miquel Raynald790f552018-05-15 11:56:59 +0200880 const u8 command[14] = {
André Draszik2c6e5ff2017-10-03 16:55:52 +0100881 0x0, 0xc1, /* TPM_TAG */
882 0x0, 0x0, 0x0, 0xe, /* parameter size */
883 0x0, 0x0, 0x0, 0x46, /* TPM_COMMAND_CODE */
884 };
885 const size_t length_offset = 10;
886 const size_t data_size_offset = 10;
887 const size_t data_offset = 14;
Miquel Raynald790f552018-05-15 11:56:59 +0200888 u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
André Draszik2c6e5ff2017-10-03 16:55:52 +0100889 size_t response_length = sizeof(response);
Miquel Raynald790f552018-05-15 11:56:59 +0200890 u32 data_size;
891 u8 *out = data;
André Draszik2c6e5ff2017-10-03 16:55:52 +0100892
893 while (count > 0) {
Miquel Raynald790f552018-05-15 11:56:59 +0200894 u32 this_bytes = min((size_t)count,
895 sizeof(response) - data_offset);
896 u32 err;
André Draszik2c6e5ff2017-10-03 16:55:52 +0100897
898 if (pack_byte_string(buf, sizeof(buf), "sd",
899 0, command, sizeof(command),
900 length_offset, this_bytes))
901 return TPM_LIB_ERROR;
Simon Glass8ceca1d2018-11-18 14:22:27 -0700902 err = tpm_sendrecv_command(dev, buf, response,
903 &response_length);
André Draszik2c6e5ff2017-10-03 16:55:52 +0100904 if (err)
905 return err;
906 if (unpack_byte_string(response, response_length, "d",
907 data_size_offset, &data_size))
908 return TPM_LIB_ERROR;
909 if (data_size > count)
910 return TPM_LIB_ERROR;
911 if (unpack_byte_string(response, response_length, "s",
912 data_offset, out, data_size))
913 return TPM_LIB_ERROR;
914
915 count -= data_size;
916 out += data_size;
917 }
918
919 return 0;
920}